consolefs.c 20 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <auth.h>
  4. #include <fcall.h>
  5. #include <bio.h>
  6. #include <ndb.h>
  7. #include <thread.h>
  8. /*
  9. * This fs presents a 1 level file system. It contains
  10. * three files per console (xxx and xxxctl and xxxstat)
  11. */
  12. typedef struct Console Console;
  13. typedef struct Fid Fid;
  14. typedef struct Request Request;
  15. typedef struct Reqlist Reqlist;
  16. typedef struct Fs Fs;
  17. enum
  18. {
  19. /* last 5 bits of qid.path */
  20. Textern= 0, /* fake parent of top level */
  21. Ttopdir, /* top level directory */
  22. Qctl,
  23. Qstat,
  24. Qdata,
  25. Bufsize= 32*1024, /* chars buffered per reader */
  26. Maxcons= 64, /* maximum consoles */
  27. Nhash= 64, /* Fid hash buckets */
  28. };
  29. #define TYPE(x) (((ulong)x.path) & 0xf)
  30. #define CONS(x) ((((ulong)x.path) >> 4)&0xfff)
  31. #define QID(c, x) (((c)<<4) | (x))
  32. struct Request
  33. {
  34. Request *next;
  35. Fid *fid;
  36. Fs *fs;
  37. Fcall f;
  38. uchar buf[1];
  39. };
  40. struct Reqlist
  41. {
  42. Lock;
  43. Request *first;
  44. Request *last;
  45. };
  46. struct Fid
  47. {
  48. Lock;
  49. Fid *next; /* hash list */
  50. Fid *cnext; /* list of Fid's on a console */
  51. int fid;
  52. int ref;
  53. int attached;
  54. int open;
  55. char *user;
  56. Qid qid;
  57. Console *c;
  58. char buf[Bufsize];
  59. char *rp;
  60. char *wp;
  61. Reqlist r; /* active read requests */
  62. };
  63. struct Console
  64. {
  65. Lock;
  66. char *name;
  67. char *dev;
  68. int speed;
  69. int cronly;
  70. int ondemand; /* open only on demand */
  71. int pid; /* pid of reader */
  72. int fd;
  73. int cfd;
  74. int sfd;
  75. Fid *flist; /* open fids to broadcast to */
  76. };
  77. struct Fs
  78. {
  79. Lock;
  80. int fd; /* to kernel mount point */
  81. int messagesize;
  82. Fid *hash[Nhash];
  83. Console *cons[Maxcons];
  84. int ncons;
  85. };
  86. extern void console(Fs*, char*, char*, int, int, int);
  87. extern Fs* fsmount(char*);
  88. extern void fsreader(void*);
  89. extern void fsrun(void*);
  90. extern Fid* fsgetfid(Fs*, int);
  91. extern void fsputfid(Fs*, Fid*);
  92. extern int fsdirgen(Fs*, Qid, int, Dir*, uchar*, int);
  93. extern void fsreply(Fs*, Request*, char*);
  94. extern void fskick(Fs*, Fid*);
  95. extern int fsreopen(Fs*, Console*);
  96. extern void fsversion(Fs*, Request*, Fid*);
  97. extern void fsflush(Fs*, Request*, Fid*);
  98. extern void fsauth(Fs*, Request*, Fid*);
  99. extern void fsattach(Fs*, Request*, Fid*);
  100. extern void fswalk(Fs*, Request*, Fid*);
  101. extern void fsclwalk(Fs*, Request*, Fid*);
  102. extern void fsopen(Fs*, Request*, Fid*);
  103. extern void fscreate(Fs*, Request*, Fid*);
  104. extern void fsread(Fs*, Request*, Fid*);
  105. extern void fswrite(Fs*, Request*, Fid*);
  106. extern void fsclunk(Fs*, Request*, Fid*);
  107. extern void fsremove(Fs*, Request*, Fid*);
  108. extern void fsstat(Fs*, Request*, Fid*);
  109. extern void fswstat(Fs*, Request*, Fid*);
  110. void (*fcall[])(Fs*, Request*, Fid*) =
  111. {
  112. [Tflush] fsflush,
  113. [Tversion] fsversion,
  114. [Tauth] fsauth,
  115. [Tattach] fsattach,
  116. [Twalk] fswalk,
  117. [Topen] fsopen,
  118. [Tcreate] fscreate,
  119. [Tread] fsread,
  120. [Twrite] fswrite,
  121. [Tclunk] fsclunk,
  122. [Tremove] fsremove,
  123. [Tstat] fsstat,
  124. [Twstat] fswstat
  125. };
  126. char Eperm[] = "permission denied";
  127. char Eexist[] = "file does not exist";
  128. char Enotdir[] = "not a directory";
  129. char Eisopen[] = "file already open";
  130. char Ebadcount[] = "bad read/write count";
  131. char Enofid[] = "no such fid";
  132. char *consoledb = "/lib/ndb/consoledb";
  133. char *mntpt = "/mnt/consoles";
  134. int messagesize = 8192+IOHDRSZ;
  135. void
  136. fatal(char *fmt, ...)
  137. {
  138. va_list arg;
  139. char buf[1024];
  140. write(2, "consolefs: ", 10);
  141. va_start(arg, fmt);
  142. vseprint(buf, buf+1024, fmt, arg);
  143. va_end(arg);
  144. write(2, buf, strlen(buf));
  145. write(2, "\n", 1);
  146. threadexitsall(fmt);
  147. }
  148. void*
  149. emalloc(uint n)
  150. {
  151. void *p;
  152. p = malloc(n);
  153. if(p == nil)
  154. fatal("malloc failed: %r");
  155. memset(p, 0, n);
  156. return p;
  157. }
  158. int debug;
  159. Ndb *db;
  160. /*
  161. * any request that can get queued for a delayed reply
  162. */
  163. Request*
  164. allocreq(Fs *fs, int bufsize)
  165. {
  166. Request *r;
  167. r = emalloc(sizeof(Request)+bufsize);
  168. r->fs = fs;
  169. r->next = nil;
  170. return r;
  171. }
  172. /*
  173. * for maintaining lists of requests
  174. */
  175. void
  176. addreq(Reqlist *l, Request *r)
  177. {
  178. lock(l);
  179. if(l->first == nil)
  180. l->first = r;
  181. else
  182. l->last->next = r;
  183. l->last = r;
  184. r->next = nil;
  185. unlock(l);
  186. }
  187. /*
  188. * remove the first request from a list of requests
  189. */
  190. Request*
  191. remreq(Reqlist *l)
  192. {
  193. Request *r;
  194. lock(l);
  195. r = l->first;
  196. if(r != nil)
  197. l->first = r->next;
  198. unlock(l);
  199. return r;
  200. }
  201. /*
  202. * remove a request with the given tag from a list of requests
  203. */
  204. Request*
  205. remtag(Reqlist *l, int tag)
  206. {
  207. Request *or, **ll;
  208. lock(l);
  209. ll = &l->first;
  210. for(or = *ll; or; or = or->next){
  211. if(or->f.tag == tag){
  212. *ll = or->next;
  213. unlock(l);
  214. return or;
  215. }
  216. ll = &or->next;
  217. }
  218. unlock(l);
  219. return nil;
  220. }
  221. Qid
  222. parentqid(Qid q)
  223. {
  224. if(q.type & QTDIR)
  225. return (Qid){QID(0, Textern), 0, QTDIR};
  226. else
  227. return (Qid){QID(0, Ttopdir), 0, QTDIR};
  228. }
  229. int
  230. fsdirgen(Fs *fs, Qid parent, int i, Dir *d, uchar *buf, int nbuf)
  231. {
  232. static char name[64];
  233. char *p;
  234. int xcons;
  235. d->uid = d->gid = d->muid = "network";
  236. d->length = 0;
  237. d->atime = time(nil);
  238. d->mtime = d->atime;
  239. d->type = 'C';
  240. d->dev = '0';
  241. switch(TYPE(parent)){
  242. case Textern:
  243. if(i != 0)
  244. return -1;
  245. p = "consoles";
  246. d->mode = DMDIR|0555;
  247. d->qid.type = QTDIR;
  248. d->qid.path = QID(0, Ttopdir);
  249. d->qid.vers = 0;
  250. break;
  251. case Ttopdir:
  252. xcons = i/3;
  253. if(xcons >= fs->ncons)
  254. return -1;
  255. p = fs->cons[xcons]->name;
  256. switch(i%3){
  257. case 0:
  258. if(fs->cons[xcons]->cfd < 0)
  259. return 0;
  260. snprint(name, sizeof name, "%sctl", p);
  261. p = name;
  262. d->qid.type = QTFILE;
  263. d->qid.path = QID(xcons, Qctl);
  264. d->qid.vers = 0;
  265. break;
  266. case 1:
  267. if(fs->cons[xcons]->sfd < 0)
  268. return 0;
  269. snprint(name, sizeof name, "%sstat", p);
  270. p = name;
  271. d->qid.type = QTFILE;
  272. d->qid.path = QID(xcons, Qstat);
  273. d->qid.vers = 0;
  274. break;
  275. case 2:
  276. d->qid.type = QTFILE;
  277. d->qid.path = QID(xcons, Qdata);
  278. d->qid.vers = 0;
  279. break;
  280. }
  281. d->mode = 0666;
  282. break;
  283. default:
  284. return -1;
  285. }
  286. d->name = p;
  287. if(buf != nil)
  288. return convD2M(d, buf, nbuf);
  289. return 1;
  290. }
  291. /*
  292. * mount the user interface and start a request processor
  293. */
  294. Fs*
  295. fsmount(char *mntpt)
  296. {
  297. Fs *fs;
  298. int pfd[2], srv;
  299. char buf[32];
  300. int n;
  301. static void *v[2];
  302. fs = emalloc(sizeof(Fs));
  303. if(pipe(pfd) < 0)
  304. fatal("opening pipe: %r");
  305. /* start up the file system process */
  306. v[0] = fs;
  307. v[1] = pfd;
  308. proccreate(fsrun, v, 16*1024);
  309. /* Typically mounted before /srv exists */
  310. if(access("#s/consoles", AEXIST) < 0){
  311. srv = create("#s/consoles", OWRITE, 0666);
  312. if(srv < 0)
  313. fatal("post: %r");
  314. n = sprint(buf, "%d", pfd[1]);
  315. if(write(srv, buf, n) < 0)
  316. fatal("write srv: %r");
  317. close(srv);
  318. }
  319. mount(pfd[1], -1, mntpt, MBEFORE, "");
  320. close(pfd[1]);
  321. return fs;
  322. }
  323. /*
  324. * reopen a console
  325. */
  326. int
  327. fsreopen(Fs* fs, Console *c)
  328. {
  329. char buf[128];
  330. static void *v[2];
  331. if(c->pid){
  332. if(postnote(PNPROC, c->pid, "reopen") != 0)
  333. fprint(2, "postnote failed: %r\n");
  334. c->pid = 0;
  335. }
  336. if(c->fd >= 0){
  337. close(c->fd);
  338. close(c->cfd);
  339. close(c->sfd);
  340. c->cfd = -1;
  341. c->fd = -1;
  342. c->sfd = -1;
  343. }
  344. if(c->flist == nil && c->ondemand)
  345. return 0;
  346. c->fd = open(c->dev, ORDWR);
  347. if(c->fd < 0)
  348. return -1;
  349. snprint(buf, sizeof(buf), "%sctl", c->dev);
  350. c->cfd = open(buf, ORDWR);
  351. fprint(c->cfd, "b%d", c->speed);
  352. snprint(buf, sizeof(buf), "%sstat", c->dev);
  353. c->sfd = open(buf, OREAD);
  354. v[0] = fs;
  355. v[1] = c;
  356. proccreate(fsreader, v, 16*1024);
  357. return 0;
  358. }
  359. void
  360. change(Fs *fs, Console *c, int doreopen, int speed, int cronly, int ondemand)
  361. {
  362. lock(c);
  363. if(speed != c->speed){
  364. c->speed = speed;
  365. doreopen = 1;
  366. }
  367. if(ondemand != c->ondemand){
  368. c->ondemand = ondemand;
  369. doreopen = 1;
  370. }
  371. c->cronly = cronly;
  372. if(doreopen)
  373. fsreopen(fs, c);
  374. unlock(c);
  375. }
  376. /*
  377. * create a console interface
  378. */
  379. void
  380. console(Fs* fs, char *name, char *dev, int speed, int cronly, int ondemand)
  381. {
  382. Console *c;
  383. char *x;
  384. int i, doreopen;
  385. if(fs->ncons >= Maxcons)
  386. fatal("too many consoles, too little time");
  387. doreopen = 0;
  388. for(i = 0; i < fs->ncons; i++){
  389. c = fs->cons[i];
  390. if(strcmp(name, c->name) == 0){
  391. if(strcmp(dev, c->dev) != 0){
  392. /* new device */
  393. x = c->dev;
  394. c->dev = strdup(dev);
  395. free(x);
  396. doreopen = 1;
  397. }
  398. change(fs, c, doreopen, speed, cronly, ondemand);
  399. return;
  400. }
  401. }
  402. for(i = 0; i < fs->ncons; i++){
  403. c = fs->cons[i];
  404. if(strcmp(dev, c->dev) == 0){
  405. /* at least a rename */
  406. x = c->name;
  407. c->name = strdup(name);
  408. free(x);
  409. change(fs, c, doreopen, speed, cronly, ondemand);
  410. return;
  411. }
  412. }
  413. c = emalloc(sizeof(Console));
  414. fs->cons[fs->ncons++] = c;
  415. c->name = strdup(name);
  416. c->dev = strdup(dev);
  417. c->fd = -1;
  418. c->cfd = -1;
  419. c->sfd = -1;
  420. change(fs, c, 1, speed, cronly, ondemand);
  421. }
  422. /*
  423. * buffer data from console to a client.
  424. * circular q with writer able to catch up to reader.
  425. * the reader may miss data but always sees an in order sequence.
  426. */
  427. void
  428. fromconsole(Fid *f, char *p, int n)
  429. {
  430. char *rp, *wp, *ep;
  431. int pass;
  432. lock(f);
  433. rp = f->rp;
  434. wp = f->wp;
  435. ep = f->buf + sizeof(f->buf);
  436. pass = 0;
  437. while(n--){
  438. *wp++ = *p++;
  439. if(wp >= ep)
  440. wp = f->buf;
  441. if(rp == wp)
  442. pass = 1;
  443. }
  444. f->wp = wp;
  445. /* we overtook the read pointer, push it up so readers always
  446. * see the tail of what was written
  447. */
  448. if(pass){
  449. wp++;
  450. if(wp >= ep)
  451. f->rp = f->buf;
  452. else
  453. f->rp = wp;
  454. }
  455. unlock(f);
  456. }
  457. /*
  458. * broadcast a list of members to all listeners
  459. */
  460. void
  461. bcastmembers(Fs *fs, Console *c, char *msg, Fid *f)
  462. {
  463. int n;
  464. Fid *fl;
  465. char buf[512];
  466. sprint(buf, "[%s%s", msg, f->user);
  467. for(fl = c->flist; fl != nil && strlen(buf) + 64 < sizeof(buf); fl = fl->cnext){
  468. if(f == fl)
  469. continue;
  470. strcat(buf, ", ");
  471. strcat(buf, fl->user);
  472. }
  473. strcat(buf, "]\n");
  474. n = strlen(buf);
  475. for(fl = c->flist; fl; fl = fl->cnext){
  476. fromconsole(fl, buf, n);
  477. fskick(fs, fl);
  478. }
  479. }
  480. void
  481. handler(void*, char *msg)
  482. {
  483. if(strstr(msg, "reopen"))
  484. noted(NCONT);
  485. noted(NDFLT);
  486. }
  487. /*
  488. * a process to read console output and broadcast it (one per console)
  489. */
  490. void
  491. fsreader(void *v)
  492. {
  493. int n;
  494. Fid *fl;
  495. char buf[1024];
  496. Fs *fs;
  497. Console *c;
  498. void **a;
  499. a = v;
  500. fs = a[0];
  501. c = a[1];
  502. c->pid = getpid();
  503. notify(handler);
  504. for(;;){
  505. n = read(c->fd, buf, sizeof(buf));
  506. if(n < 0)
  507. break;
  508. lock(c);
  509. for(fl = c->flist; fl; fl = fl->cnext){
  510. fromconsole(fl, buf, n);
  511. fskick(fs, fl);
  512. }
  513. unlock(c);
  514. }
  515. }
  516. void
  517. readdb(Fs *fs)
  518. {
  519. Ndbtuple *t, *nt;
  520. char *dev, *cons;
  521. int cronly, speed, ondemand;
  522. ndbreopen(db);
  523. /* start a listener for each console */
  524. for(;;){
  525. t = ndbparse(db);
  526. if(t == nil)
  527. break;
  528. dev = nil;
  529. cons = nil;
  530. speed = 9600;
  531. cronly = 0;
  532. ondemand = 0;
  533. for(nt = t; nt; nt = nt->entry){
  534. if(strcmp(nt->attr, "console") == 0)
  535. cons = nt->val;
  536. else if(strcmp(nt->attr, "dev") == 0)
  537. dev = nt->val;
  538. else if(strcmp(nt->attr, "speed") == 0)
  539. speed = atoi(nt->val);
  540. else if(strcmp(nt->attr, "cronly") == 0)
  541. cronly = 1;
  542. else if(strcmp(nt->attr, "openondemand") == 0)
  543. ondemand = 1;
  544. }
  545. if(dev != nil && cons != nil)
  546. console(fs, cons, dev, speed, cronly, ondemand);
  547. ndbfree(t);
  548. }
  549. }
  550. int dbmtime;
  551. /*
  552. * a request processor (one per Fs)
  553. */
  554. void
  555. fsrun(void *v)
  556. {
  557. int n, t;
  558. Request *r;
  559. Fid *f;
  560. Dir *d;
  561. void **a = v;
  562. Fs* fs;
  563. int *pfd;
  564. fs = a[0];
  565. pfd = a[1];
  566. fs->fd = pfd[0];
  567. for(;;){
  568. d = dirstat(consoledb);
  569. if(d != nil && d->mtime != dbmtime){
  570. dbmtime = d->mtime;
  571. readdb(fs);
  572. }
  573. free(d);
  574. r = allocreq(fs, messagesize);
  575. n = read9pmsg(fs->fd, r->buf, messagesize);
  576. if(n <= 0)
  577. fatal("unmounted");
  578. if(convM2S(r->buf, n, &r->f) == 0){
  579. fprint(2, "can't convert %ux %ux %ux\n", r->buf[0],
  580. r->buf[1], r->buf[2]);
  581. free(r);
  582. continue;
  583. }
  584. f = fsgetfid(fs, r->f.fid);
  585. r->fid = f;
  586. if(debug)
  587. fprint(2, "%F path %llux\n", &r->f, f->qid.path);
  588. t = r->f.type;
  589. r->f.type++;
  590. (*fcall[t])(fs, r, f);
  591. }
  592. }
  593. Fid*
  594. fsgetfid(Fs *fs, int fid)
  595. {
  596. Fid *f, *nf;
  597. lock(fs);
  598. for(f = fs->hash[fid%Nhash]; f; f = f->next){
  599. if(f->fid == fid){
  600. f->ref++;
  601. unlock(fs);
  602. return f;
  603. }
  604. }
  605. nf = emalloc(sizeof(Fid));
  606. nf->next = fs->hash[fid%Nhash];
  607. fs->hash[fid%Nhash] = nf;
  608. nf->fid = fid;
  609. nf->ref = 1;
  610. nf->wp = nf->buf;
  611. nf->rp = nf->wp;
  612. unlock(fs);
  613. return nf;
  614. }
  615. void
  616. fsputfid(Fs *fs, Fid *f)
  617. {
  618. Fid **l, *nf;
  619. lock(fs);
  620. if(--f->ref > 0){
  621. unlock(fs);
  622. return;
  623. }
  624. for(l = &fs->hash[f->fid%Nhash]; nf = *l; l = &nf->next)
  625. if(nf == f){
  626. *l = f->next;
  627. break;
  628. }
  629. unlock(fs);
  630. free(f->user);
  631. free(f);
  632. }
  633. void
  634. fsauth(Fs *fs, Request *r, Fid*)
  635. {
  636. fsreply(fs, r, "consolefs: authentication not required");
  637. }
  638. void
  639. fsversion(Fs *fs, Request *r, Fid*)
  640. {
  641. if(r->f.msize < 256){
  642. fsreply(fs, r, "message size too small");
  643. return;
  644. }
  645. messagesize = r->f.msize;
  646. if(messagesize > 8192+IOHDRSZ)
  647. messagesize = 8192+IOHDRSZ;
  648. r->f.msize = messagesize;
  649. if(strncmp(r->f.version, "9P2000", 6) != 0){
  650. fsreply(fs, r, "unrecognized 9P version");
  651. return;
  652. }
  653. r->f.version = "9P2000";
  654. fsreply(fs, r, nil);
  655. }
  656. void
  657. fsflush(Fs *fs, Request *r, Fid *f)
  658. {
  659. Request *or;
  660. or = remtag(&f->r, r->f.oldtag);
  661. if(or != nil){
  662. fsputfid(fs, or->fid);
  663. free(or);
  664. }
  665. fsreply(fs, r, nil);
  666. }
  667. void
  668. fsattach(Fs *fs, Request *r, Fid *f)
  669. {
  670. f->qid.type = QTDIR;
  671. f->qid.path = QID(0, Ttopdir);
  672. f->qid.vers = 0;
  673. if(r->f.uname[0])
  674. f->user = strdup(r->f.uname);
  675. else
  676. f->user = strdup("none");
  677. /* hold down the fid till the clunk */
  678. f->attached = 1;
  679. lock(fs);
  680. f->ref++;
  681. unlock(fs);
  682. r->f.qid = f->qid;
  683. fsreply(fs, r, nil);
  684. }
  685. void
  686. fswalk(Fs *fs, Request *r, Fid *f)
  687. {
  688. char *name;
  689. Dir d;
  690. int i, n, nqid, nwname;
  691. Qid qid, wqid[MAXWELEM];
  692. Fid *nf;
  693. char *err;
  694. if(f->attached == 0){
  695. fsreply(fs, r, Enofid);
  696. return;
  697. }
  698. nf = nil;
  699. if(r->f.fid != r->f.newfid){
  700. nf = fsgetfid(fs, r->f.newfid);
  701. nf->attached = f->attached;
  702. nf->open = f->open;
  703. nf->qid = f->qid;
  704. nf->user = strdup(f->user);
  705. nf->c = f->c;
  706. nf->wp = nf->buf;
  707. nf->rp = nf->wp;
  708. f = nf;
  709. }
  710. qid = f->qid;
  711. err = nil;
  712. nwname = r->f.nwname;
  713. nqid = 0;
  714. if(nwname > 0){
  715. for(; err == nil && nqid < nwname; nqid++){
  716. if(nqid >= MAXWELEM){
  717. err = "too many name elements";
  718. break;
  719. }
  720. name = r->f.wname[nqid];
  721. if(strcmp(name, "..") == 0)
  722. qid = parentqid(qid);
  723. else if(strcmp(name, ".") != 0){
  724. for(i = 0; ; i++){
  725. n = fsdirgen(fs, qid, i, &d, nil, 0);
  726. if(n < 0){
  727. err = Eexist;
  728. break;
  729. }
  730. if(n > 0 && strcmp(name, d.name) == 0){
  731. qid = d.qid;
  732. break;
  733. }
  734. }
  735. }
  736. wqid[nqid] = qid;
  737. }
  738. if(nf != nil && nqid < nwname)
  739. fsputfid(fs, nf);
  740. if(nqid == nwname)
  741. f->qid = qid;
  742. }
  743. memmove(r->f.wqid, wqid, nqid*sizeof(Qid));
  744. r->f.nwqid = nqid;
  745. fsreply(fs, r, err);
  746. }
  747. int
  748. ingroup(char *user, char *group)
  749. {
  750. Ndbtuple *t, *nt;
  751. Ndbs s;
  752. t = ndbsearch(db, &s, "group", group);
  753. if(t == nil)
  754. return 0;
  755. for(nt = t; nt; nt = nt->entry){
  756. if(strcmp(nt->attr, "uid") == 0)
  757. if(strcmp(nt->val, user) == 0)
  758. break;
  759. }
  760. ndbfree(t);
  761. return nt != nil;
  762. }
  763. int
  764. userok(char *u, char *cname)
  765. {
  766. Ndbtuple *t, *nt;
  767. Ndbs s;
  768. t = ndbsearch(db, &s, "console", cname);
  769. if(t == nil)
  770. return 0;
  771. for(nt = t; nt; nt = nt->entry){
  772. if(strcmp(nt->attr, "uid") == 0)
  773. if(strcmp(nt->val, u) == 0)
  774. break;
  775. if(strcmp(nt->attr, "gid") == 0)
  776. if(ingroup(u, nt->val))
  777. break;
  778. }
  779. ndbfree(t);
  780. return nt != nil;
  781. }
  782. int m2p[] ={
  783. [OREAD] 4,
  784. [OWRITE] 2,
  785. [ORDWR] 6
  786. };
  787. void
  788. fsopen(Fs *fs, Request *r, Fid *f)
  789. {
  790. int mode;
  791. Console *c;
  792. if(f->attached == 0){
  793. fsreply(fs, r, Enofid);
  794. return;
  795. }
  796. if(f->open){
  797. fsreply(fs, r, Eisopen);
  798. return;
  799. }
  800. mode = r->f.mode & 3;
  801. if((QTDIR & f->qid.type) && mode != OREAD){
  802. fsreply(fs, r, Eperm);
  803. return;
  804. }
  805. switch(TYPE(f->qid)){
  806. case Qdata:
  807. c = fs->cons[CONS(f->qid)];
  808. if(!userok(f->user, c->name)){
  809. fsreply(fs, r, Eperm);
  810. return;
  811. }
  812. f->rp = f->buf;
  813. f->wp = f->buf;
  814. f->c = c;
  815. lock(c);
  816. f->cnext = c->flist;
  817. c->flist = f;
  818. bcastmembers(fs, c, "+", f);
  819. if(c->pid == 0)
  820. fsreopen(fs, c);
  821. unlock(c);
  822. break;
  823. case Qctl:
  824. c = fs->cons[CONS(f->qid)];
  825. if(!userok(f->user, c->name)){
  826. fsreply(fs, r, Eperm);
  827. return;
  828. }
  829. f->c = c;
  830. break;
  831. case Qstat:
  832. c = fs->cons[CONS(f->qid)];
  833. if(!userok(f->user, c->name)){
  834. fsreply(fs, r, Eperm);
  835. return;
  836. }
  837. f->c = c;
  838. break;
  839. }
  840. f->open = 1;
  841. r->f.iounit = messagesize-IOHDRSZ;
  842. r->f.qid = f->qid;
  843. fsreply(fs, r, nil);
  844. }
  845. void
  846. fscreate(Fs *fs, Request *r, Fid*)
  847. {
  848. fsreply(fs, r, Eperm);
  849. }
  850. void
  851. fsread(Fs *fs, Request *r, Fid *f)
  852. {
  853. uchar *p, *e;
  854. int i, m, off;
  855. vlong offset;
  856. Dir d;
  857. char sbuf[ERRMAX];
  858. if(f->attached == 0){
  859. fsreply(fs, r, Enofid);
  860. return;
  861. }
  862. if(r->f.count < 0){
  863. fsreply(fs, r, Ebadcount);
  864. return;
  865. }
  866. if(QTDIR & f->qid.type){
  867. p = r->buf + IOHDRSZ;
  868. e = p + r->f.count;
  869. offset = r->f.offset;
  870. off = 0;
  871. for(i=0; p<e; i++, off+=m){
  872. m = fsdirgen(fs, f->qid, i, &d, p, e-p);
  873. if(m < 0)
  874. break;
  875. if(m > BIT16SZ && off >= offset)
  876. p += m;
  877. }
  878. r->f.data = (char*)r->buf + IOHDRSZ;
  879. r->f.count = (char*)p - r->f.data;
  880. } else {
  881. switch(TYPE(f->qid)){
  882. case Qdata:
  883. addreq(&f->r, r);
  884. fskick(fs, f);
  885. return;
  886. case Qctl:
  887. r->f.data = (char*)r->buf+IOHDRSZ;
  888. r->f.count = 0;
  889. break;
  890. case Qstat:
  891. if(r->f.count > sizeof(sbuf))
  892. r->f.count = sizeof(sbuf);
  893. i = pread(f->c->sfd, sbuf, r->f.count, r->f.offset);
  894. if(i < 0){
  895. errstr(sbuf, sizeof sbuf);
  896. fsreply(fs, r, sbuf);
  897. return;
  898. }
  899. r->f.data = sbuf;
  900. r->f.count = i;
  901. break;
  902. default:
  903. fsreply(fs, r, Eexist);
  904. return;
  905. }
  906. }
  907. fsreply(fs, r, nil);
  908. }
  909. void
  910. fswrite(Fs *fs, Request *r, Fid *f)
  911. {
  912. int i;
  913. if(f->attached == 0){
  914. fsreply(fs, r, Enofid);
  915. return;
  916. }
  917. if(r->f.count < 0){
  918. fsreply(fs, r, Ebadcount);
  919. return;
  920. }
  921. if(QTDIR & f->qid.type){
  922. fsreply(fs, r, Eperm);
  923. return;
  924. }
  925. switch(TYPE(f->qid)){
  926. default:
  927. fsreply(fs, r, Eperm);
  928. return;
  929. case Qctl:
  930. write(f->c->cfd, r->f.data, r->f.count);
  931. break;
  932. case Qdata:
  933. if(f->c->cronly)
  934. for(i = 0; i < r->f.count; i++)
  935. if(r->f.data[i] == '\n')
  936. r->f.data[i] = '\r';
  937. write(f->c->fd, r->f.data, r->f.count);
  938. break;
  939. }
  940. fsreply(fs, r, nil);
  941. }
  942. void
  943. fsclunk(Fs *fs, Request *r, Fid *f)
  944. {
  945. Fid **l, *fl;
  946. Request *nr;
  947. if(f->open && TYPE(f->qid) == Qdata){
  948. while((nr = remreq(&f->r)) != nil){
  949. fsputfid(fs, f);
  950. free(nr);
  951. }
  952. lock(f->c);
  953. for(l = &f->c->flist; *l; l = &fl->cnext){
  954. fl = *l;
  955. if(fl == f){
  956. *l = fl->cnext;
  957. break;
  958. }
  959. }
  960. bcastmembers(fs, f->c, "-", f);
  961. if(f->c->ondemand && f->c->flist == nil)
  962. fsreopen(fs, f->c);
  963. unlock(f->c);
  964. }
  965. fsreply(fs, r, nil);
  966. fsputfid(fs, f);
  967. }
  968. void
  969. fsremove(Fs *fs, Request *r, Fid*)
  970. {
  971. fsreply(fs, r, Eperm);
  972. }
  973. void
  974. fsstat(Fs *fs, Request *r, Fid *f)
  975. {
  976. int i;
  977. Qid q;
  978. Dir d;
  979. q = parentqid(f->qid);
  980. for(i = 0; ; i++){
  981. r->f.stat = r->buf+IOHDRSZ;
  982. r->f.nstat = fsdirgen(fs, q, i, &d, r->f.stat, messagesize-IOHDRSZ);
  983. if(r->f.nstat < 0){
  984. fsreply(fs, r, Eexist);
  985. return;
  986. }
  987. if(r->f.nstat > BIT16SZ && d.qid.path == f->qid.path)
  988. break;
  989. }
  990. fsreply(fs, r, nil);
  991. }
  992. void
  993. fswstat(Fs *fs, Request *r, Fid*)
  994. {
  995. fsreply(fs, r, Eperm);
  996. }
  997. void
  998. fsreply(Fs *fs, Request *r, char *err)
  999. {
  1000. int n;
  1001. uchar buf[8192+IOHDRSZ];
  1002. if(err){
  1003. r->f.type = Rerror;
  1004. r->f.ename = err;
  1005. }
  1006. n = convS2M(&r->f, buf, messagesize);
  1007. if(debug)
  1008. fprint(2, "%F path %llux n=%d\n", &r->f, r->fid->qid.path, n);
  1009. fsputfid(fs, r->fid);
  1010. if(write(fs->fd, buf, n) != n)
  1011. fatal("unmounted");
  1012. free(r);
  1013. }
  1014. /*
  1015. * called whenever input or a read request has been received
  1016. */
  1017. void
  1018. fskick(Fs *fs, Fid *f)
  1019. {
  1020. Request *r;
  1021. char *p, *rp, *wp, *ep;
  1022. int i;
  1023. lock(f);
  1024. while(f->rp != f->wp){
  1025. r = remreq(&f->r);
  1026. if(r == nil)
  1027. break;
  1028. p = (char*)r->buf;
  1029. rp = f->rp;
  1030. wp = f->wp;
  1031. ep = &f->buf[Bufsize];
  1032. for(i = 0; i < r->f.count && rp != wp; i++){
  1033. *p++ = *rp++;
  1034. if(rp >= ep)
  1035. rp = f->buf;
  1036. }
  1037. f->rp = rp;
  1038. r->f.data = (char*)r->buf;
  1039. r->f.count = p - (char*)r->buf;
  1040. fsreply(fs, r, nil);
  1041. }
  1042. unlock(f);
  1043. }
  1044. void
  1045. usage(void)
  1046. {
  1047. fprint(2, "usage: consolefs [-d] [-m mount-point] [-c console-db]\n");
  1048. threadexitsall("usage");
  1049. }
  1050. void
  1051. threadmain(int argc, char **argv)
  1052. {
  1053. fmtinstall('F', fcallfmt);
  1054. ARGBEGIN{
  1055. case 'd':
  1056. debug++;
  1057. break;
  1058. case 'c':
  1059. consoledb = ARGF();
  1060. if(consoledb == nil)
  1061. usage();
  1062. break;
  1063. case 'm':
  1064. mntpt = ARGF();
  1065. if(mntpt == nil)
  1066. usage();
  1067. break;
  1068. }ARGEND;
  1069. db = ndbopen(consoledb);
  1070. if(db == nil)
  1071. fatal("can't open %s: %r", consoledb);
  1072. fsmount(mntpt);
  1073. }