consolefs.c 20 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225
  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. fs->ncons++;
  416. c->name = strdup(name);
  417. c->dev = strdup(dev);
  418. c->fd = -1;
  419. c->cfd = -1;
  420. c->sfd = -1;
  421. change(fs, c, 1, speed, cronly, ondemand);
  422. }
  423. /*
  424. * buffer data from console to a client.
  425. * circular q with writer able to catch up to reader.
  426. * the reader may miss data but always sees an in order sequence.
  427. */
  428. void
  429. fromconsole(Fid *f, char *p, int n)
  430. {
  431. char *rp, *wp, *ep;
  432. int pass;
  433. lock(f);
  434. rp = f->rp;
  435. wp = f->wp;
  436. ep = f->buf + sizeof(f->buf);
  437. pass = 0;
  438. while(n--){
  439. *wp++ = *p++;
  440. if(wp >= ep)
  441. wp = f->buf;
  442. if(rp == wp)
  443. pass = 1;
  444. }
  445. f->wp = wp;
  446. /* we overtook the read pointer, push it up so readers always
  447. * see the tail of what was written
  448. */
  449. if(pass){
  450. wp++;
  451. if(wp >= ep)
  452. f->rp = f->buf;
  453. else
  454. f->rp = wp;
  455. }
  456. unlock(f);
  457. }
  458. /*
  459. * broadcast a list of members to all listeners
  460. */
  461. void
  462. bcastmembers(Fs *fs, Console *c, char *msg, Fid *f)
  463. {
  464. int n;
  465. Fid *fl;
  466. char buf[512];
  467. sprint(buf, "[%s%s", msg, f->user);
  468. for(fl = c->flist; fl != nil && strlen(buf) + 64 < sizeof(buf); fl = fl->cnext){
  469. if(f == fl)
  470. continue;
  471. strcat(buf, ", ");
  472. strcat(buf, fl->user);
  473. }
  474. strcat(buf, "]\n");
  475. n = strlen(buf);
  476. for(fl = c->flist; fl; fl = fl->cnext){
  477. fromconsole(fl, buf, n);
  478. fskick(fs, fl);
  479. }
  480. }
  481. void
  482. handler(void*, char *msg)
  483. {
  484. if(strstr(msg, "reopen"))
  485. noted(NCONT);
  486. noted(NDFLT);
  487. }
  488. /*
  489. * a process to read console output and broadcast it (one per console)
  490. */
  491. void
  492. fsreader(void *v)
  493. {
  494. int n;
  495. Fid *fl;
  496. char buf[1024];
  497. Fs *fs;
  498. Console *c;
  499. void **a;
  500. a = v;
  501. fs = a[0];
  502. c = a[1];
  503. c->pid = getpid();
  504. notify(handler);
  505. for(;;){
  506. n = read(c->fd, buf, sizeof(buf));
  507. if(n < 0)
  508. break;
  509. lock(c);
  510. for(fl = c->flist; fl; fl = fl->cnext){
  511. fromconsole(fl, buf, n);
  512. fskick(fs, fl);
  513. }
  514. unlock(c);
  515. }
  516. }
  517. void
  518. readdb(Fs *fs)
  519. {
  520. Ndbtuple *t, *nt;
  521. char *dev, *cons;
  522. int cronly, speed, ondemand;
  523. ndbreopen(db);
  524. /* start a listener for each console */
  525. for(;;){
  526. t = ndbparse(db);
  527. if(t == nil)
  528. break;
  529. dev = nil;
  530. cons = nil;
  531. speed = 9600;
  532. cronly = 0;
  533. ondemand = 0;
  534. for(nt = t; nt; nt = nt->entry){
  535. if(strcmp(nt->attr, "console") == 0)
  536. cons = nt->val;
  537. else if(strcmp(nt->attr, "dev") == 0)
  538. dev = nt->val;
  539. else if(strcmp(nt->attr, "speed") == 0)
  540. speed = atoi(nt->val);
  541. else if(strcmp(nt->attr, "cronly") == 0)
  542. cronly = 1;
  543. else if(strcmp(nt->attr, "openondemand") == 0)
  544. ondemand = 1;
  545. }
  546. if(dev != nil && cons != nil)
  547. console(fs, cons, dev, speed, cronly, ondemand);
  548. ndbfree(t);
  549. }
  550. }
  551. int dbmtime;
  552. /*
  553. * a request processor (one per Fs)
  554. */
  555. void
  556. fsrun(void *v)
  557. {
  558. int n, t;
  559. Request *r;
  560. Fid *f;
  561. Dir *d;
  562. void **a = v;
  563. Fs* fs;
  564. int *pfd;
  565. fs = a[0];
  566. pfd = a[1];
  567. fs->fd = pfd[0];
  568. for(;;){
  569. d = dirstat(consoledb);
  570. if(d != nil && d->mtime != dbmtime){
  571. dbmtime = d->mtime;
  572. readdb(fs);
  573. }
  574. free(d);
  575. r = allocreq(fs, messagesize);
  576. n = read9pmsg(fs->fd, r->buf, messagesize);
  577. if(n <= 0)
  578. fatal("unmounted");
  579. if(convM2S(r->buf, n, &r->f) == 0){
  580. fprint(2, "can't convert %ux %ux %ux\n", r->buf[0],
  581. r->buf[1], r->buf[2]);
  582. free(r);
  583. continue;
  584. }
  585. f = fsgetfid(fs, r->f.fid);
  586. r->fid = f;
  587. if(debug)
  588. fprint(2, "%F path %llux\n", &r->f, f->qid.path);
  589. t = r->f.type;
  590. r->f.type++;
  591. (*fcall[t])(fs, r, f);
  592. }
  593. }
  594. Fid*
  595. fsgetfid(Fs *fs, int fid)
  596. {
  597. Fid *f, *nf;
  598. lock(fs);
  599. for(f = fs->hash[fid%Nhash]; f; f = f->next){
  600. if(f->fid == fid){
  601. f->ref++;
  602. unlock(fs);
  603. return f;
  604. }
  605. }
  606. nf = emalloc(sizeof(Fid));
  607. nf->next = fs->hash[fid%Nhash];
  608. fs->hash[fid%Nhash] = nf;
  609. nf->fid = fid;
  610. nf->ref = 1;
  611. nf->wp = nf->buf;
  612. nf->rp = nf->wp;
  613. unlock(fs);
  614. return nf;
  615. }
  616. void
  617. fsputfid(Fs *fs, Fid *f)
  618. {
  619. Fid **l, *nf;
  620. lock(fs);
  621. if(--f->ref > 0){
  622. unlock(fs);
  623. return;
  624. }
  625. for(l = &fs->hash[f->fid%Nhash]; nf = *l; l = &nf->next)
  626. if(nf == f){
  627. *l = f->next;
  628. break;
  629. }
  630. unlock(fs);
  631. free(f->user);
  632. free(f);
  633. }
  634. void
  635. fsauth(Fs *fs, Request *r, Fid*)
  636. {
  637. fsreply(fs, r, "consolefs: authentication not required");
  638. }
  639. void
  640. fsversion(Fs *fs, Request *r, Fid*)
  641. {
  642. if(r->f.msize < 256){
  643. fsreply(fs, r, "message size too small");
  644. return;
  645. }
  646. messagesize = r->f.msize;
  647. if(messagesize > 8192+IOHDRSZ)
  648. messagesize = 8192+IOHDRSZ;
  649. r->f.msize = messagesize;
  650. if(strncmp(r->f.version, "9P2000", 6) != 0){
  651. fsreply(fs, r, "unrecognized 9P version");
  652. return;
  653. }
  654. r->f.version = "9P2000";
  655. fsreply(fs, r, nil);
  656. }
  657. void
  658. fsflush(Fs *fs, Request *r, Fid *f)
  659. {
  660. Request *or;
  661. or = remtag(&f->r, r->f.oldtag);
  662. if(or != nil){
  663. fsputfid(fs, or->fid);
  664. free(or);
  665. }
  666. fsreply(fs, r, nil);
  667. }
  668. void
  669. fsattach(Fs *fs, Request *r, Fid *f)
  670. {
  671. f->qid.type = QTDIR;
  672. f->qid.path = QID(0, Ttopdir);
  673. f->qid.vers = 0;
  674. if(r->f.uname[0])
  675. f->user = strdup(r->f.uname);
  676. else
  677. f->user = strdup("none");
  678. /* hold down the fid till the clunk */
  679. f->attached = 1;
  680. lock(fs);
  681. f->ref++;
  682. unlock(fs);
  683. r->f.qid = f->qid;
  684. fsreply(fs, r, nil);
  685. }
  686. void
  687. fswalk(Fs *fs, Request *r, Fid *f)
  688. {
  689. char *name;
  690. Dir d;
  691. int i, n, nqid, nwname;
  692. Qid qid, wqid[MAXWELEM];
  693. Fid *nf;
  694. char *err;
  695. if(f->attached == 0){
  696. fsreply(fs, r, Enofid);
  697. return;
  698. }
  699. nf = nil;
  700. if(r->f.fid != r->f.newfid){
  701. nf = fsgetfid(fs, r->f.newfid);
  702. nf->attached = f->attached;
  703. nf->open = f->open;
  704. nf->qid = f->qid;
  705. nf->user = strdup(f->user);
  706. nf->c = f->c;
  707. nf->wp = nf->buf;
  708. nf->rp = nf->wp;
  709. f = nf;
  710. }
  711. qid = f->qid;
  712. err = nil;
  713. nwname = r->f.nwname;
  714. nqid = 0;
  715. if(nwname > 0){
  716. for(; err == nil && nqid < nwname; nqid++){
  717. if(nqid >= MAXWELEM){
  718. err = "too many name elements";
  719. break;
  720. }
  721. name = r->f.wname[nqid];
  722. if(strcmp(name, "..") == 0)
  723. qid = parentqid(qid);
  724. else if(strcmp(name, ".") != 0){
  725. for(i = 0; ; i++){
  726. n = fsdirgen(fs, qid, i, &d, nil, 0);
  727. if(n < 0){
  728. err = Eexist;
  729. break;
  730. }
  731. if(n > 0 && strcmp(name, d.name) == 0){
  732. qid = d.qid;
  733. break;
  734. }
  735. }
  736. }
  737. wqid[nqid] = qid;
  738. }
  739. if(nf != nil && nqid < nwname)
  740. fsputfid(fs, nf);
  741. if(nqid == nwname)
  742. f->qid = qid;
  743. }
  744. memmove(r->f.wqid, wqid, nqid*sizeof(Qid));
  745. r->f.nwqid = nqid;
  746. fsreply(fs, r, err);
  747. }
  748. int
  749. ingroup(char *user, char *group)
  750. {
  751. Ndbtuple *t, *nt;
  752. Ndbs s;
  753. t = ndbsearch(db, &s, "group", group);
  754. if(t == nil)
  755. return 0;
  756. for(nt = t; nt; nt = nt->entry){
  757. if(strcmp(nt->attr, "uid") == 0)
  758. if(strcmp(nt->val, user) == 0)
  759. break;
  760. }
  761. ndbfree(t);
  762. return nt != nil;
  763. }
  764. int
  765. userok(char *u, char *cname)
  766. {
  767. Ndbtuple *t, *nt;
  768. Ndbs s;
  769. t = ndbsearch(db, &s, "console", cname);
  770. if(t == nil)
  771. return 0;
  772. for(nt = t; nt; nt = nt->entry){
  773. if(strcmp(nt->attr, "uid") == 0)
  774. if(strcmp(nt->val, u) == 0)
  775. break;
  776. if(strcmp(nt->attr, "gid") == 0)
  777. if(ingroup(u, nt->val))
  778. break;
  779. }
  780. ndbfree(t);
  781. return nt != nil;
  782. }
  783. int m2p[] ={
  784. [OREAD] 4,
  785. [OWRITE] 2,
  786. [ORDWR] 6
  787. };
  788. void
  789. fsopen(Fs *fs, Request *r, Fid *f)
  790. {
  791. int mode;
  792. Console *c;
  793. if(f->attached == 0){
  794. fsreply(fs, r, Enofid);
  795. return;
  796. }
  797. if(f->open){
  798. fsreply(fs, r, Eisopen);
  799. return;
  800. }
  801. mode = r->f.mode & 3;
  802. if((QTDIR & f->qid.type) && mode != OREAD){
  803. fsreply(fs, r, Eperm);
  804. return;
  805. }
  806. switch(TYPE(f->qid)){
  807. case Qdata:
  808. c = fs->cons[CONS(f->qid)];
  809. if(!userok(f->user, c->name)){
  810. fsreply(fs, r, Eperm);
  811. return;
  812. }
  813. f->rp = f->buf;
  814. f->wp = f->buf;
  815. f->c = c;
  816. lock(c);
  817. f->cnext = c->flist;
  818. c->flist = f;
  819. bcastmembers(fs, c, "+", f);
  820. if(c->pid == 0)
  821. fsreopen(fs, c);
  822. unlock(c);
  823. break;
  824. case Qctl:
  825. c = fs->cons[CONS(f->qid)];
  826. if(!userok(f->user, c->name)){
  827. fsreply(fs, r, Eperm);
  828. return;
  829. }
  830. f->c = c;
  831. break;
  832. case Qstat:
  833. c = fs->cons[CONS(f->qid)];
  834. if(!userok(f->user, c->name)){
  835. fsreply(fs, r, Eperm);
  836. return;
  837. }
  838. f->c = c;
  839. break;
  840. }
  841. f->open = 1;
  842. r->f.iounit = messagesize-IOHDRSZ;
  843. r->f.qid = f->qid;
  844. fsreply(fs, r, nil);
  845. }
  846. void
  847. fscreate(Fs *fs, Request *r, Fid*)
  848. {
  849. fsreply(fs, r, Eperm);
  850. }
  851. void
  852. fsread(Fs *fs, Request *r, Fid *f)
  853. {
  854. uchar *p, *e;
  855. int i, m, off;
  856. vlong offset;
  857. Dir d;
  858. char sbuf[ERRMAX];
  859. if(f->attached == 0){
  860. fsreply(fs, r, Enofid);
  861. return;
  862. }
  863. if((int)r->f.count < 0){
  864. fsreply(fs, r, Ebadcount);
  865. return;
  866. }
  867. if(QTDIR & f->qid.type){
  868. p = r->buf + IOHDRSZ;
  869. e = p + r->f.count;
  870. offset = r->f.offset;
  871. off = 0;
  872. for(i=0; p<e; i++, off+=m){
  873. m = fsdirgen(fs, f->qid, i, &d, p, e-p);
  874. if(m < 0)
  875. break;
  876. if(m > BIT16SZ && off >= offset)
  877. p += m;
  878. }
  879. r->f.data = (char*)r->buf + IOHDRSZ;
  880. r->f.count = (char*)p - r->f.data;
  881. } else {
  882. switch(TYPE(f->qid)){
  883. case Qdata:
  884. addreq(&f->r, r);
  885. fskick(fs, f);
  886. return;
  887. case Qctl:
  888. r->f.data = (char*)r->buf+IOHDRSZ;
  889. r->f.count = 0;
  890. break;
  891. case Qstat:
  892. if(r->f.count > sizeof(sbuf))
  893. r->f.count = sizeof(sbuf);
  894. i = pread(f->c->sfd, sbuf, r->f.count, r->f.offset);
  895. if(i < 0){
  896. errstr(sbuf, sizeof sbuf);
  897. fsreply(fs, r, sbuf);
  898. return;
  899. }
  900. r->f.data = sbuf;
  901. r->f.count = i;
  902. break;
  903. default:
  904. fsreply(fs, r, Eexist);
  905. return;
  906. }
  907. }
  908. fsreply(fs, r, nil);
  909. }
  910. void
  911. fswrite(Fs *fs, Request *r, Fid *f)
  912. {
  913. int i;
  914. if(f->attached == 0){
  915. fsreply(fs, r, Enofid);
  916. return;
  917. }
  918. if((int)r->f.count < 0){
  919. fsreply(fs, r, Ebadcount);
  920. return;
  921. }
  922. if(QTDIR & f->qid.type){
  923. fsreply(fs, r, Eperm);
  924. return;
  925. }
  926. switch(TYPE(f->qid)){
  927. default:
  928. fsreply(fs, r, Eperm);
  929. return;
  930. case Qctl:
  931. write(f->c->cfd, r->f.data, r->f.count);
  932. break;
  933. case Qdata:
  934. if(f->c->cronly)
  935. for(i = 0; i < r->f.count; i++)
  936. if(r->f.data[i] == '\n')
  937. r->f.data[i] = '\r';
  938. write(f->c->fd, r->f.data, r->f.count);
  939. break;
  940. }
  941. fsreply(fs, r, nil);
  942. }
  943. void
  944. fsclunk(Fs *fs, Request *r, Fid *f)
  945. {
  946. Fid **l, *fl;
  947. Request *nr;
  948. if(f->open && TYPE(f->qid) == Qdata){
  949. while((nr = remreq(&f->r)) != nil){
  950. fsputfid(fs, f);
  951. free(nr);
  952. }
  953. lock(f->c);
  954. for(l = &f->c->flist; *l; l = &fl->cnext){
  955. fl = *l;
  956. if(fl == f){
  957. *l = fl->cnext;
  958. break;
  959. }
  960. }
  961. bcastmembers(fs, f->c, "-", f);
  962. if(f->c->ondemand && f->c->flist == nil)
  963. fsreopen(fs, f->c);
  964. unlock(f->c);
  965. }
  966. fsreply(fs, r, nil);
  967. fsputfid(fs, f);
  968. }
  969. void
  970. fsremove(Fs *fs, Request *r, Fid*)
  971. {
  972. fsreply(fs, r, Eperm);
  973. }
  974. void
  975. fsstat(Fs *fs, Request *r, Fid *f)
  976. {
  977. int i, n;
  978. Qid q;
  979. Dir d;
  980. q = parentqid(f->qid);
  981. for(i = 0; ; i++){
  982. r->f.stat = r->buf+IOHDRSZ;
  983. n = fsdirgen(fs, q, i, &d, r->f.stat, messagesize-IOHDRSZ);
  984. if(n < 0){
  985. fsreply(fs, r, Eexist);
  986. return;
  987. }
  988. r->f.nstat = n;
  989. if(r->f.nstat > BIT16SZ && d.qid.path == f->qid.path)
  990. break;
  991. }
  992. fsreply(fs, r, nil);
  993. }
  994. void
  995. fswstat(Fs *fs, Request *r, Fid*)
  996. {
  997. fsreply(fs, r, Eperm);
  998. }
  999. void
  1000. fsreply(Fs *fs, Request *r, char *err)
  1001. {
  1002. int n;
  1003. uchar buf[8192+IOHDRSZ];
  1004. if(err){
  1005. r->f.type = Rerror;
  1006. r->f.ename = err;
  1007. }
  1008. n = convS2M(&r->f, buf, messagesize);
  1009. if(debug)
  1010. fprint(2, "%F path %llux n=%d\n", &r->f, r->fid->qid.path, n);
  1011. fsputfid(fs, r->fid);
  1012. if(write(fs->fd, buf, n) != n)
  1013. fatal("unmounted");
  1014. free(r);
  1015. }
  1016. /*
  1017. * called whenever input or a read request has been received
  1018. */
  1019. void
  1020. fskick(Fs *fs, Fid *f)
  1021. {
  1022. Request *r;
  1023. char *p, *rp, *wp, *ep;
  1024. int i;
  1025. lock(f);
  1026. while(f->rp != f->wp){
  1027. r = remreq(&f->r);
  1028. if(r == nil)
  1029. break;
  1030. p = (char*)r->buf;
  1031. rp = f->rp;
  1032. wp = f->wp;
  1033. ep = &f->buf[Bufsize];
  1034. for(i = 0; i < r->f.count && rp != wp; i++){
  1035. *p++ = *rp++;
  1036. if(rp >= ep)
  1037. rp = f->buf;
  1038. }
  1039. f->rp = rp;
  1040. r->f.data = (char*)r->buf;
  1041. r->f.count = p - (char*)r->buf;
  1042. fsreply(fs, r, nil);
  1043. }
  1044. unlock(f);
  1045. }
  1046. void
  1047. usage(void)
  1048. {
  1049. fprint(2, "usage: consolefs [-d] [-m mount-point] [-c console-db]\n");
  1050. threadexitsall("usage");
  1051. }
  1052. void
  1053. threadmain(int argc, char **argv)
  1054. {
  1055. fmtinstall('F', fcallfmt);
  1056. ARGBEGIN{
  1057. case 'd':
  1058. debug++;
  1059. break;
  1060. case 'c':
  1061. consoledb = ARGF();
  1062. if(consoledb == nil)
  1063. usage();
  1064. break;
  1065. case 'm':
  1066. mntpt = ARGF();
  1067. if(mntpt == nil)
  1068. usage();
  1069. break;
  1070. }ARGEND;
  1071. db = ndbopen(consoledb);
  1072. if(db == nil)
  1073. fatal("can't open %s: %r", consoledb);
  1074. fsmount(mntpt);
  1075. }