consolefs.c 21 KB

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