srv.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <auth.h>
  4. #include <fcall.h>
  5. #include <thread.h>
  6. #include <9p.h>
  7. static char Ebadattach[] = "unknown specifier in attach";
  8. static char Ebadoffset[] = "bad offset";
  9. static char Ebadcount[] = "bad count";
  10. static char Ebotch[] = "9P protocol botch";
  11. static char Ecreatenondir[] = "create in non-directory";
  12. static char Edupfid[] = "duplicate fid";
  13. static char Eduptag[] = "duplicate tag";
  14. static char Eisdir[] = "is a directory";
  15. static char Enocreate[] = "create prohibited";
  16. static char Enomem[] = "out of memory";
  17. static char Enoremove[] = "remove prohibited";
  18. static char Enostat[] = "stat prohibited";
  19. static char Enotfound[] = "file not found";
  20. static char Enowrite[] = "write prohibited";
  21. static char Enowstat[] = "wstat prohibited";
  22. static char Eperm[] = "permission denied";
  23. static char Eunknownfid[] = "unknown fid";
  24. static char Ebaddir[] = "bad directory in wstat";
  25. static char Ewalknodir[] = "walk in non-directory";
  26. static void
  27. setfcallerror(Fcall *f, char *err)
  28. {
  29. f->ename = err;
  30. f->type = Rerror;
  31. }
  32. static void
  33. changemsize(Srv *srv, int msize)
  34. {
  35. if(srv->rbuf && srv->wbuf && srv->msize == msize)
  36. return;
  37. qlock(&srv->rlock);
  38. qlock(&srv->wlock);
  39. srv->msize = msize;
  40. free(srv->rbuf);
  41. free(srv->wbuf);
  42. srv->rbuf = emalloc9p(msize);
  43. srv->wbuf = emalloc9p(msize);
  44. if(srv->rbuf==nil || srv->wbuf==nil)
  45. sysfatal("out of memory"); /* BUG */
  46. qunlock(&srv->rlock);
  47. qunlock(&srv->wlock);
  48. }
  49. static Req*
  50. getreq(Srv *s)
  51. {
  52. long n;
  53. uchar *buf;
  54. Fcall f;
  55. Req *r;
  56. qlock(&s->rlock);
  57. if((n = read9pmsg(s->infd, s->rbuf, s->msize)) <= 0){
  58. qunlock(&s->rlock);
  59. return nil;
  60. }
  61. buf = emalloc9p(n);
  62. memmove(buf, s->rbuf, n);
  63. qunlock(&s->rlock);
  64. if(convM2S(buf, n, &f) != n){
  65. free(buf);
  66. return nil;
  67. }
  68. if((r=allocreq(s->rpool, f.tag)) == nil){ /* duplicate tag: cons up a fake Req */
  69. r = emalloc9p(sizeof *r);
  70. incref(&r->ref);
  71. r->tag = f.tag;
  72. r->ifcall = f;
  73. r->error = Eduptag;
  74. r->buf = buf;
  75. r->responded = 0;
  76. r->type = 0;
  77. r->srv = s;
  78. r->pool = nil;
  79. if(chatty9p)
  80. fprint(2, "<-%d- %F: dup tag\n", s->infd, &f);
  81. return r;
  82. }
  83. r->srv = s;
  84. r->responded = 0;
  85. r->buf = buf;
  86. r->ifcall = f;
  87. memset(&r->ofcall, 0, sizeof r->ofcall);
  88. r->type = r->ifcall.type;
  89. if(chatty9p)
  90. if(r->error)
  91. fprint(2, "<-%d- %F: %s\n", s->infd, &r->ifcall, r->error);
  92. else
  93. fprint(2, "<-%d- %F\n", s->infd, &r->ifcall);
  94. return r;
  95. }
  96. static void
  97. filewalk(Req *r)
  98. {
  99. int i;
  100. File *f;
  101. f = r->fid->file;
  102. assert(f != nil);
  103. incref(f);
  104. for(i=0; i<r->ifcall.nwname; i++)
  105. if(f = walkfile(f, r->ifcall.wname[i]))
  106. r->ofcall.wqid[i] = f->qid;
  107. else
  108. break;
  109. r->ofcall.nwqid = i;
  110. if(f){
  111. r->newfid->file = f;
  112. r->newfid->qid = r->newfid->file->qid;
  113. }
  114. respond(r, nil);
  115. }
  116. static void
  117. conswalk(Req *r, char *(*clone)(Fid*, Fid*), char *(*walk1)(Fid*, char*, Qid*))
  118. {
  119. int i;
  120. char *e;
  121. if(r->fid == r->newfid && r->ifcall.nwname > 1){
  122. respond(r, "lib9p: unused documented feature not implemented");
  123. return;
  124. }
  125. if(r->fid != r->newfid){
  126. r->newfid->qid = r->fid->qid;
  127. if(clone && (e = clone(r->fid, r->newfid))){
  128. respond(r, e);
  129. return;
  130. }
  131. }
  132. e = nil;
  133. for(i=0; i<r->ifcall.nwname; i++){
  134. if(e = walk1(r->newfid, r->ifcall.wname[i], &r->ofcall.wqid[i]))
  135. break;
  136. r->newfid->qid = r->ofcall.wqid[i];
  137. }
  138. r->ofcall.nwqid = i;
  139. if(e && i==0)
  140. respond(r, e);
  141. else
  142. respond(r, nil);
  143. }
  144. void
  145. srv(Srv *srv)
  146. {
  147. int o, p;
  148. Req *r;
  149. char e[ERRMAX];
  150. fmtinstall('D', dirfmt);
  151. fmtinstall('F', fcallfmt);
  152. if(srv->fpool == nil)
  153. srv->fpool = allocfidpool(srv->destroyfid);
  154. if(srv->rpool == nil)
  155. srv->rpool = allocreqpool(srv->destroyreq);
  156. if(srv->msize == 0)
  157. srv->msize = 8192+IOHDRSZ;
  158. changemsize(srv, srv->msize);
  159. srv->fpool->srv = srv;
  160. srv->rpool->srv = srv;
  161. while(r = getreq(srv)){
  162. if(r->error){
  163. respond(r, r->error);
  164. continue;
  165. }
  166. switch(r->type){
  167. default:
  168. respond(r, "unknown message");
  169. break;
  170. case Tversion:
  171. if(strncmp(r->ifcall.version, "9P", 2) != 0){
  172. r->ofcall.version = "unknown";
  173. respond(r, nil);
  174. break;
  175. }
  176. r->ofcall.version = "9P2000";
  177. r->ofcall.msize = r->ifcall.msize;
  178. respond(r, nil);
  179. break;
  180. case Tauth:
  181. if((r->afid = allocfid(srv->fpool, r->ifcall.afid)) == nil){
  182. respond(r, Edupfid);
  183. break;
  184. }
  185. if(srv->auth)
  186. srv->auth(r);
  187. else{
  188. snprint(e, sizeof e, "%s: authentication not required", argv0);
  189. respond(r, e);
  190. }
  191. break;
  192. case Tattach:
  193. if((r->fid = allocfid(srv->fpool, r->ifcall.fid)) == nil){
  194. respond(r, Edupfid);
  195. break;
  196. }
  197. r->afid = nil;
  198. if(r->ifcall.afid != NOFID && (r->afid = lookupfid(srv->fpool, r->ifcall.afid)) == nil){
  199. respond(r, Eunknownfid);
  200. break;
  201. }
  202. r->fid->uid = estrdup9p(r->ifcall.uname);
  203. if(srv->tree){
  204. r->fid->file = srv->tree->root;
  205. /* BUG? incref(r->fid->file) ??? */
  206. r->ofcall.qid = r->fid->file->qid;
  207. r->fid->qid = r->ofcall.qid;
  208. }
  209. if(srv->attach)
  210. srv->attach(r);
  211. else
  212. respond(r, nil);
  213. break;
  214. case Tflush:
  215. r->oldreq = lookupreq(srv->rpool, r->ifcall.oldtag);
  216. if(r->oldreq == nil || r->oldreq == r)
  217. respond(r, nil);
  218. else if(srv->flush)
  219. srv->flush(r);
  220. else
  221. sysfatal("outstanding message but flush not provided");
  222. break;
  223. case Twalk:
  224. if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
  225. respond(r, Eunknownfid);
  226. break;
  227. }
  228. if(r->fid->omode != -1){
  229. respond(r, "cannot clone open fid");
  230. break;
  231. }
  232. if(r->ifcall.nwname && !(r->fid->qid.type&QTDIR)){
  233. respond(r, Ewalknodir);
  234. break;
  235. }
  236. if(r->ifcall.fid != r->ifcall.newfid){
  237. if((r->newfid = allocfid(srv->fpool, r->ifcall.newfid)) == nil){
  238. respond(r, Edupfid);
  239. break;
  240. }
  241. r->newfid->uid = estrdup9p(r->fid->uid);
  242. }else{
  243. incref(&r->fid->ref);
  244. r->newfid = r->fid;
  245. }
  246. if(r->fid->file){
  247. filewalk(r);
  248. }else if(srv->walk1)
  249. conswalk(r, srv->clone, srv->walk1);
  250. else if(srv->walk)
  251. srv->walk(r);
  252. else
  253. sysfatal("no walk function, no file trees");
  254. break;
  255. case Topen:
  256. if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
  257. respond(r, Eunknownfid);
  258. break;
  259. }
  260. if(r->fid->omode != -1){
  261. respond(r, Ebotch);
  262. break;
  263. }
  264. if((r->fid->qid.type&QTDIR) && (r->ifcall.mode&~ORCLOSE) != OREAD){
  265. respond(r, Eisdir);
  266. break;
  267. }
  268. r->ofcall.qid = r->fid->qid;
  269. switch(r->ifcall.mode&3){
  270. default:
  271. assert(0);
  272. case OREAD:
  273. p = AREAD;
  274. break;
  275. case OWRITE:
  276. p = AWRITE;
  277. break;
  278. case ORDWR:
  279. p = AREAD|AWRITE;
  280. break;
  281. case OEXEC:
  282. p = AEXEC;
  283. break;
  284. }
  285. if(r->ifcall.mode&OTRUNC)
  286. p |= AWRITE;
  287. if((r->fid->qid.type&QTDIR) && p!=AREAD){
  288. respond(r, Eperm);
  289. break;
  290. }
  291. if(r->fid->file){
  292. if(!hasperm(r->fid->file, r->fid->uid, p)){
  293. respond(r, Eperm);
  294. break;
  295. }
  296. /* BUG RACE */
  297. if((r->ifcall.mode&ORCLOSE)
  298. && !hasperm(r->fid->file->parent, r->fid->uid, AWRITE)){
  299. respond(r, Eperm);
  300. break;
  301. }
  302. r->ofcall.qid = r->fid->file->qid;
  303. if((r->ofcall.qid.type&QTDIR)
  304. && (r->fid->rdir = opendirfile(r->fid->file)) == nil){
  305. respond(r, "opendirfile failed");
  306. break;
  307. }
  308. }
  309. if(srv->open)
  310. srv->open(r);
  311. else
  312. respond(r, nil);
  313. break;
  314. case Tcreate:
  315. if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil)
  316. respond(r, Eunknownfid);
  317. else if(r->fid->omode != -1)
  318. respond(r, Ebotch);
  319. else if(!(r->fid->qid.type&QTDIR))
  320. respond(r, Ecreatenondir);
  321. else if(r->fid->file && !hasperm(r->fid->file, r->fid->uid, AWRITE))
  322. respond(r, Eperm);
  323. else if(srv->create)
  324. srv->create(r);
  325. else
  326. respond(r, Enocreate);
  327. break;
  328. case Tread:
  329. if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
  330. respond(r, Eunknownfid);
  331. break;
  332. }
  333. if(r->ifcall.count < 0){
  334. respond(r, Ebotch);
  335. break;
  336. }
  337. if(r->ifcall.offset < 0
  338. || ((r->fid->qid.type&QTDIR) && r->ifcall.offset != 0 && r->ifcall.offset != r->fid->diroffset)){
  339. respond(r, Ebadoffset);
  340. break;
  341. }
  342. if(r->ifcall.count > srv->msize - IOHDRSZ)
  343. r->ifcall.count = srv->msize - IOHDRSZ;
  344. if((r->rbuf = emalloc9p(r->ifcall.count)) == nil){
  345. respond(r, Enomem);
  346. break;
  347. }
  348. r->ofcall.data = r->rbuf;
  349. o = r->fid->omode & 3;
  350. if(o != OREAD && o != ORDWR && o != OEXEC){
  351. respond(r, Ebotch);
  352. break;
  353. }
  354. if((r->fid->qid.type&QTDIR) && r->fid->file){
  355. r->ofcall.count = readdirfile(r->fid->rdir, r->rbuf, r->ifcall.count);
  356. respond(r, nil);
  357. break;
  358. }
  359. if(srv->read)
  360. srv->read(r);
  361. else
  362. respond(r, "no srv->read");
  363. break;
  364. case Twrite:
  365. if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
  366. respond(r, Eunknownfid);
  367. break;
  368. }
  369. if(r->ifcall.count < 0){
  370. respond(r, Ebotch);
  371. break;
  372. }
  373. if(r->ifcall.offset < 0){
  374. respond(r, Ebotch);
  375. break;
  376. }
  377. if(r->ifcall.count > srv->msize - IOHDRSZ)
  378. r->ifcall.count = srv->msize - IOHDRSZ;
  379. o = r->fid->omode & 3;
  380. if(o != OWRITE && o != ORDWR){
  381. snprint(e, sizeof e, "write on fid with open mode 0x%ux", r->fid->omode);
  382. respond(r, e);
  383. break;
  384. }
  385. if(srv->write)
  386. srv->write(r);
  387. else
  388. respond(r, "no srv->write");
  389. break;
  390. case Tclunk:
  391. if((r->fid = removefid(srv->fpool, r->ifcall.fid)) == nil)
  392. respond(r, Eunknownfid);
  393. else
  394. respond(r, nil);
  395. break;
  396. case Tremove:
  397. if((r->fid = removefid(srv->fpool, r->ifcall.fid)) == nil){
  398. respond(r, Eunknownfid);
  399. break;
  400. }
  401. /* BUG RACE */
  402. if(r->fid->file && !hasperm(r->fid->file->parent, r->fid->uid, AWRITE)){
  403. respond(r, Eperm);
  404. break;
  405. }
  406. if(srv->remove)
  407. srv->remove(r);
  408. else
  409. respond(r, r->fid->file ? nil : Enoremove);
  410. break;
  411. case Tstat:
  412. if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
  413. respond(r, Eunknownfid);
  414. break;
  415. }
  416. if(r->fid->file){
  417. r->d = r->fid->file->Dir;
  418. if(r->d.name)
  419. r->d.name = estrdup9p(r->d.name);
  420. if(r->d.uid)
  421. r->d.uid = estrdup9p(r->d.uid);
  422. if(r->d.gid)
  423. r->d.gid = estrdup9p(r->d.gid);
  424. if(r->d.muid)
  425. r->d.muid = estrdup9p(r->d.muid);
  426. }
  427. if(srv->stat)
  428. srv->stat(r);
  429. else if(r->fid->file)
  430. respond(r, nil);
  431. else
  432. respond(r, Enostat);
  433. break;
  434. case Twstat:
  435. if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil)
  436. respond(r, Eunknownfid);
  437. else if(srv->wstat){
  438. if(convM2D(r->ifcall.stat, r->ifcall.nstat, &r->d, (char*)r->ifcall.stat) != r->ifcall.nstat)
  439. respond(r, Ebaddir);
  440. else
  441. srv->wstat(r);
  442. }else
  443. respond(r, Enowstat);
  444. break;
  445. }
  446. }
  447. if(srv->end)
  448. srv->end(srv);
  449. }
  450. void
  451. respond(Req *r, char *error)
  452. {
  453. int m, n;
  454. Req *or;
  455. uchar *statbuf, tmp[BIT16SZ];
  456. char errbuf[ERRMAX];
  457. Srv *srv;
  458. srv = r->srv;
  459. assert(srv != nil);
  460. assert(r->responded == 0);
  461. r->responded = 1;
  462. switch(r->ifcall.type){
  463. default:
  464. assert(0);
  465. case Tversion:
  466. assert(error == nil);
  467. changemsize(srv, r->ofcall.msize);
  468. break;
  469. case Tauth:
  470. if(error){
  471. if(r->afid)
  472. closefid(removefid(srv->fpool, r->afid->fid));
  473. break;
  474. }
  475. break;
  476. case Tattach:
  477. if(error){
  478. if(r->fid)
  479. closefid(removefid(srv->fpool, r->fid->fid));
  480. break;
  481. }
  482. break;
  483. case Tflush:
  484. assert(error == nil);
  485. if(r->oldreq){
  486. if(or = removereq(r->pool, r->oldreq->tag)){
  487. assert(or == r->oldreq);
  488. if(or->ifcall.type == Twalk && or->ifcall.fid != or->ifcall.newfid)
  489. closefid(removefid(srv->fpool, or->newfid->fid));
  490. closereq(or);
  491. }
  492. closereq(r->oldreq);
  493. }
  494. r->oldreq = nil;
  495. break;
  496. case Twalk:
  497. if(error || r->ofcall.nwqid < r->ifcall.nwname){
  498. if(r->ifcall.fid != r->ifcall.newfid && r->newfid)
  499. closefid(removefid(srv->fpool, r->newfid->fid));
  500. if (r->ofcall.nwqid==0){
  501. if(error==nil && r->ifcall.nwname!=0)
  502. error = Enotfound;
  503. }else
  504. error = nil; // No error on partial walks
  505. break;
  506. }else{
  507. if(r->ofcall.nwqid == 0){
  508. /* Just a clone */
  509. r->newfid->qid = r->fid->qid;
  510. }else{
  511. /* if file trees are in use, filewalk took care of the rest */
  512. r->newfid->qid = r->ofcall.wqid[r->ofcall.nwqid-1];
  513. }
  514. }
  515. break;
  516. case Topen:
  517. if(error){
  518. break;
  519. }
  520. if(chatty9p){
  521. snprint(errbuf, sizeof errbuf, "fid mode is 0x%ux\n", r->ifcall.mode);
  522. write(2, errbuf, strlen(errbuf));
  523. }
  524. r->fid->omode = r->ifcall.mode;
  525. r->fid->qid = r->ofcall.qid;
  526. if(r->ofcall.qid.type&QTDIR)
  527. r->fid->diroffset = 0;
  528. break;
  529. case Tcreate:
  530. if(error){
  531. break;
  532. }
  533. r->fid->omode = r->ifcall.mode;
  534. r->fid->qid = r->ofcall.qid;
  535. break;
  536. case Tread:
  537. if(error==nil && (r->fid->qid.type&QTDIR))
  538. r->fid->diroffset += r->ofcall.count;
  539. break;
  540. case Twrite:
  541. if(error)
  542. break;
  543. if(r->fid->file)
  544. r->fid->file->qid.vers++;
  545. break;
  546. case Tclunk:
  547. break;
  548. case Tremove:
  549. if(error)
  550. break;
  551. if(r->fid->file){
  552. if(removefile(r->fid->file) < 0){
  553. snprint(errbuf, ERRMAX, "remove %s: %r",
  554. r->fid->file->name);
  555. error = errbuf;
  556. }
  557. r->fid->file = nil;
  558. }
  559. break;
  560. case Tstat:
  561. if(error)
  562. break;
  563. if(convD2M(&r->d, tmp, BIT16SZ) != BIT16SZ){
  564. error = "convD2M(_,_,BIT16SZ) did not return BIT16SZ";
  565. break;
  566. }
  567. n = GBIT16(tmp)+BIT16SZ;
  568. statbuf = emalloc9p(n);
  569. if(statbuf == nil){
  570. error = "out of memory";
  571. break;
  572. }
  573. r->ofcall.nstat = convD2M(&r->d, statbuf, n);
  574. r->ofcall.stat = statbuf;
  575. if(r->ofcall.nstat < 0){
  576. error = "convD2M fails";
  577. break;
  578. }
  579. break;
  580. case Twstat:
  581. break;
  582. }
  583. r->ofcall.tag = r->ifcall.tag;
  584. r->ofcall.type = r->ifcall.type+1;
  585. if(error)
  586. setfcallerror(&r->ofcall, error);
  587. if(chatty9p)
  588. fprint(2, "-%d-> %F\n", srv->outfd, &r->ofcall);
  589. qlock(&srv->wlock);
  590. n = convS2M(&r->ofcall, srv->wbuf, srv->msize);
  591. if(n <= 0){
  592. fprint(2, "n = %d %F\n", n, &r->ofcall);
  593. abort();
  594. }
  595. assert(n > 2);
  596. if(r->pool){ /* not a fake */
  597. closereq(removereq(r->pool, r->ifcall.tag));
  598. closereq(r);
  599. }else
  600. free(r);
  601. m = write(srv->outfd, srv->wbuf, n);
  602. if(m != n)
  603. sysfatal("lib9p srv: write %d returned %d on fd %d: %r", n, m, srv->outfd);
  604. qunlock(&srv->wlock);
  605. }
  606. int
  607. postfd(char *name, int pfd)
  608. {
  609. int fd;
  610. char buf[80];
  611. snprint(buf, sizeof buf, "/srv/%s", name);
  612. if(chatty9p)
  613. fprint(2, "postfd %s\n", buf);
  614. fd = create(buf, OWRITE|ORCLOSE|OCEXEC, 0600);
  615. if(fd < 0){
  616. if(chatty9p)
  617. fprint(2, "create fails: %r\n");
  618. return -1;
  619. }
  620. if(fprint(fd, "%d", pfd) < 0){
  621. if(chatty9p)
  622. fprint(2, "write fails: %r\n");
  623. close(fd);
  624. return -1;
  625. }
  626. if(chatty9p)
  627. fprint(2, "postfd successful\n");
  628. return 0;
  629. }