exportfs.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942
  1. /*
  2. * exportfs - Export a plan 9 name space across a network
  3. */
  4. #include <u.h>
  5. #include <libc.h>
  6. #include <auth.h>
  7. #include <fcall.h>
  8. #include <libsec.h>
  9. #define Extern
  10. #include "exportfs.h"
  11. #define QIDPATH ((1LL<<48)-1)
  12. vlong newqid = 0;
  13. enum {
  14. Encnone,
  15. Encssl,
  16. Enctls,
  17. };
  18. void (*fcalls[])(Fsrpc*) =
  19. {
  20. [Tversion] Xversion,
  21. [Tauth] Xauth,
  22. [Tflush] Xflush,
  23. [Tattach] Xattach,
  24. [Twalk] Xwalk,
  25. [Topen] slave,
  26. [Tcreate] Xcreate,
  27. [Tclunk] Xclunk,
  28. [Tread] slave,
  29. [Twrite] slave,
  30. [Tremove] Xremove,
  31. [Tstat] Xstat,
  32. [Twstat] Xwstat,
  33. };
  34. /* accounting and debugging counters */
  35. int filecnt;
  36. int freecnt;
  37. int qidcnt;
  38. int qfreecnt;
  39. int ncollision;
  40. int netfd; /* initially stdin */
  41. int srvfd = -1;
  42. int nonone = 1;
  43. char *filterp;
  44. char *ealgs = "rc4_256 sha1";
  45. char *aanfilter = "/bin/aan";
  46. int encproto = Encnone;
  47. int readonly;
  48. static void mksecret(char *, uchar *);
  49. static int localread9pmsg(int, void *, uint, ulong *);
  50. static char *anstring = "tcp!*!0";
  51. char *netdir = "", *local = "", *remote = "";
  52. int filter(int, char *);
  53. void
  54. usage(void)
  55. {
  56. fprint(2, "usage: %s [-adnsR] [-f dbgfile] [-m msize] [-r root] "
  57. "[-S srvfile] [-e 'crypt hash'] [-P exclusion-file] "
  58. "[-A announce-string] [-B address]\n", argv0);
  59. fatal("usage");
  60. }
  61. static void
  62. noteconn(int fd)
  63. {
  64. NetConnInfo *nci;
  65. nci = getnetconninfo(nil, fd);
  66. if (nci == nil)
  67. return;
  68. netdir = strdup(nci->dir);
  69. local = strdup(nci->lsys);
  70. remote = strdup(nci->rsys);
  71. freenetconninfo(nci);
  72. }
  73. void
  74. main(int argc, char **argv)
  75. {
  76. char buf[ERRMAX], ebuf[ERRMAX], *srvfdfile;
  77. Fsrpc *r;
  78. int doauth, n, fd;
  79. char *dbfile, *srv, *na, *nsfile, *keyspec;
  80. AuthInfo *ai;
  81. ulong initial;
  82. dbfile = "/tmp/exportdb";
  83. srv = nil;
  84. srvfd = -1;
  85. srvfdfile = nil;
  86. na = nil;
  87. nsfile = nil;
  88. keyspec = "";
  89. doauth = 0;
  90. ai = nil;
  91. ARGBEGIN{
  92. case 'a':
  93. doauth = 1;
  94. break;
  95. case 'd':
  96. dbg++;
  97. break;
  98. case 'e':
  99. ealgs = EARGF(usage());
  100. if(*ealgs == 0 || strcmp(ealgs, "clear") == 0)
  101. ealgs = nil;
  102. break;
  103. case 'f':
  104. dbfile = EARGF(usage());
  105. break;
  106. case 'k':
  107. keyspec = EARGF(usage());
  108. break;
  109. case 'm':
  110. messagesize = strtoul(EARGF(usage()), nil, 0);
  111. break;
  112. case 'n':
  113. nonone = 0;
  114. break;
  115. case 'r':
  116. srv = EARGF(usage());
  117. break;
  118. case 's':
  119. srv = "/";
  120. break;
  121. case 'A':
  122. anstring = EARGF(usage());
  123. break;
  124. case 'B':
  125. na = EARGF(usage());
  126. break;
  127. case 'F':
  128. /* accepted but ignored, for backwards compatibility */
  129. break;
  130. case 'N':
  131. nsfile = EARGF(usage());
  132. break;
  133. case 'P':
  134. patternfile = EARGF(usage());
  135. break;
  136. case 'R':
  137. readonly = 1;
  138. break;
  139. case 'S':
  140. if(srvfdfile)
  141. usage();
  142. srvfdfile = EARGF(usage());
  143. break;
  144. default:
  145. usage();
  146. }ARGEND
  147. USED(argc, argv);
  148. if(doauth){
  149. /*
  150. * We use p9any so we don't have to visit this code again, with the
  151. * cost that this code is incompatible with the old world, which
  152. * requires p9sk2. (The two differ in who talks first, so compatibility
  153. * is awkward.)
  154. */
  155. ai = auth_proxy(0, auth_getkey, "proto=p9any role=server %s", keyspec);
  156. if(ai == nil)
  157. fatal("auth_proxy: %r");
  158. if(nonone && strcmp(ai->cuid, "none") == 0)
  159. fatal("exportfs by none disallowed");
  160. if(auth_chuid(ai, nsfile) < 0)
  161. fatal("auth_chuid: %r");
  162. putenv("service", "exportfs");
  163. }
  164. if(srvfdfile){
  165. if((srvfd = open(srvfdfile, ORDWR)) < 0)
  166. sysfatal("open '%s': %r", srvfdfile);
  167. }
  168. if(na){
  169. if(srv == nil)
  170. sysfatal("-B requires -s");
  171. local = "me";
  172. remote = na;
  173. if((fd = dial(netmkaddr(na, 0, "importfs"), 0, 0, 0)) < 0)
  174. sysfatal("can't dial %s: %r", na);
  175. ai = auth_proxy(fd, auth_getkey, "proto=p9any role=client %s", keyspec);
  176. if(ai == nil)
  177. sysfatal("%r: %s", na);
  178. dup(fd, 0);
  179. dup(fd, 1);
  180. close(fd);
  181. }
  182. exclusions();
  183. if(dbg) {
  184. n = create(dbfile, OWRITE|OTRUNC, 0666);
  185. dup(n, DFD);
  186. close(n);
  187. }
  188. if(srvfd >= 0 && srv){
  189. fprint(2, "exportfs: -S cannot be used with -r or -s\n");
  190. usage();
  191. }
  192. DEBUG(DFD, "exportfs: started\n");
  193. rfork(RFNOTEG);
  194. if(messagesize == 0){
  195. messagesize = iounit(netfd);
  196. if(messagesize == 0)
  197. messagesize = 8192+IOHDRSZ;
  198. }
  199. Workq = emallocz(sizeof(Fsrpc)*Nr_workbufs);
  200. // for(i=0; i<Nr_workbufs; i++)
  201. // Workq[i].buf = emallocz(messagesize);
  202. fhash = emallocz(sizeof(Fid*)*FHASHSIZE);
  203. fmtinstall('F', fcallfmt);
  204. /*
  205. * Get tree to serve from network connection,
  206. * check we can get there and ack the connection
  207. */
  208. if(srvfd != -1) {
  209. /* do nothing */
  210. }
  211. else if(srv) {
  212. if(chdir(srv) < 0) {
  213. errstr(ebuf, sizeof ebuf);
  214. fprint(0, "chdir(\"%s\"): %s\n", srv, ebuf);
  215. DEBUG(DFD, "chdir(\"%s\"): %s\n", srv, ebuf);
  216. exits(ebuf);
  217. }
  218. DEBUG(DFD, "invoked as server for %s", srv);
  219. strncpy(buf, srv, sizeof buf);
  220. }
  221. else {
  222. noteconn(netfd);
  223. buf[0] = 0;
  224. n = read(0, buf, sizeof(buf)-1);
  225. if(n < 0) {
  226. errstr(buf, sizeof buf);
  227. fprint(0, "read(0): %s\n", buf);
  228. DEBUG(DFD, "read(0): %s\n", buf);
  229. exits(buf);
  230. }
  231. buf[n] = 0;
  232. if(chdir(buf) < 0) {
  233. errstr(ebuf, sizeof ebuf);
  234. fprint(0, "chdir(%d:\"%s\"): %s\n", n, buf, ebuf);
  235. DEBUG(DFD, "chdir(%d:\"%s\"): %s\n", n, buf, ebuf);
  236. exits(ebuf);
  237. }
  238. }
  239. DEBUG(DFD, "\niniting root\n");
  240. initroot();
  241. DEBUG(DFD, "exportfs: %s\n", buf);
  242. if(srv == nil && srvfd == -1 && write(0, "OK", 2) != 2)
  243. fatal("open ack write");
  244. if (readn(netfd, &initial, sizeof(ulong)) < sizeof(ulong))
  245. fatal("can't read initial string: %r\n");
  246. if (strncmp((char *)&initial, "impo", sizeof(ulong)) == 0) {
  247. char buf[128], *p, *args[3];
  248. /* New import. Read import's parameters... */
  249. initial = 0;
  250. p = buf;
  251. while (p - buf < sizeof buf) {
  252. if ((n = read(netfd, p, 1)) < 0)
  253. fatal("can't read impo arguments: %r\n");
  254. if (n == 0)
  255. fatal("connection closed while reading arguments\n");
  256. if (*p == '\n')
  257. *p = '\0';
  258. if (*p++ == '\0')
  259. break;
  260. }
  261. if (tokenize(buf, args, nelem(args)) != 2)
  262. fatal("impo arguments invalid: impo%s...\n", buf);
  263. if (strcmp(args[0], "aan") == 0)
  264. filterp = aanfilter;
  265. else if (strcmp(args[0], "nofilter") != 0)
  266. fatal("import filter argument unsupported: %s\n", args[0]);
  267. if (strcmp(args[1], "ssl") == 0)
  268. encproto = Encssl;
  269. else if (strcmp(args[1], "tls") == 0)
  270. encproto = Enctls;
  271. else if (strcmp(args[1], "clear") != 0)
  272. fatal("import encryption proto unsupported: %s\n", args[1]);
  273. if (encproto == Enctls)
  274. sysfatal("%s: tls has not yet been implemented", argv[0]);
  275. }
  276. if (encproto != Encnone && ealgs && ai) {
  277. uchar key[16];
  278. uchar digest[SHA1dlen];
  279. char fromclientsecret[21];
  280. char fromserversecret[21];
  281. int i;
  282. memmove(key+4, ai->secret, ai->nsecret);
  283. /* exchange random numbers */
  284. srand(truerand());
  285. for(i = 0; i < 4; i++)
  286. key[i+12] = rand();
  287. if (initial)
  288. fatal("Protocol botch: old import\n");
  289. if(readn(netfd, key, 4) != 4)
  290. fatal("can't read key part; %r\n");
  291. if(write(netfd, key+12, 4) != 4)
  292. fatal("can't write key part; %r\n");
  293. /* scramble into two secrets */
  294. sha1(key, sizeof(key), digest, nil);
  295. mksecret(fromclientsecret, digest);
  296. mksecret(fromserversecret, digest+10);
  297. if (filterp)
  298. netfd = filter(netfd, filterp);
  299. switch (encproto) {
  300. case Encssl:
  301. netfd = pushssl(netfd, ealgs, fromserversecret,
  302. fromclientsecret, nil);
  303. break;
  304. case Enctls:
  305. default:
  306. fatal("Unsupported encryption protocol\n");
  307. }
  308. if(netfd < 0)
  309. fatal("can't establish ssl connection: %r");
  310. }
  311. else if (filterp) {
  312. if (initial)
  313. fatal("Protocol botch: don't know how to deal with this\n");
  314. netfd = filter(netfd, filterp);
  315. }
  316. /*
  317. * Start serving file requests from the network
  318. */
  319. for(;;) {
  320. r = getsbuf();
  321. if(r == 0)
  322. fatal("Out of service buffers");
  323. n = localread9pmsg(netfd, r->buf, messagesize, &initial);
  324. if(n <= 0)
  325. fatal(nil);
  326. if(convM2S(r->buf, n, &r->work) == 0)
  327. fatal("convM2S format error");
  328. DEBUG(DFD, "%F\n", &r->work);
  329. (fcalls[r->work.type])(r);
  330. }
  331. }
  332. /*
  333. * WARNING: Replace this with the original version as soon as all
  334. * _old_ imports have been replaced with negotiating imports. Also
  335. * cpu relies on this (which needs to be fixed!) -- pb.
  336. */
  337. static int
  338. localread9pmsg(int fd, void *abuf, uint n, ulong *initial)
  339. {
  340. int m, len;
  341. uchar *buf;
  342. buf = abuf;
  343. /* read count */
  344. assert(BIT32SZ == sizeof(ulong));
  345. if (*initial) {
  346. memcpy(buf, initial, BIT32SZ);
  347. *initial = 0;
  348. }
  349. else {
  350. m = readn(fd, buf, BIT32SZ);
  351. if(m != BIT32SZ){
  352. if(m < 0)
  353. return -1;
  354. return 0;
  355. }
  356. }
  357. len = GBIT32(buf);
  358. if(len <= BIT32SZ || len > n){
  359. werrstr("bad length in 9P2000 message header");
  360. return -1;
  361. }
  362. len -= BIT32SZ;
  363. m = readn(fd, buf+BIT32SZ, len);
  364. if(m < len)
  365. return 0;
  366. return BIT32SZ+m;
  367. }
  368. void
  369. reply(Fcall *r, Fcall *t, char *err)
  370. {
  371. uchar *data;
  372. int n;
  373. t->tag = r->tag;
  374. t->fid = r->fid;
  375. if(err) {
  376. t->type = Rerror;
  377. t->ename = err;
  378. }
  379. else
  380. t->type = r->type + 1;
  381. DEBUG(DFD, "\t%F\n", t);
  382. data = malloc(messagesize); /* not mallocz; no need to clear */
  383. if(data == nil)
  384. fatal(Enomem);
  385. n = convS2M(t, data, messagesize);
  386. if(write(netfd, data, n)!=n)
  387. {syslog(0, "exportfs", "short write: %r");
  388. fatal("mount write");
  389. }
  390. free(data);
  391. }
  392. Fid *
  393. getfid(int nr)
  394. {
  395. Fid *f;
  396. for(f = fidhash(nr); f; f = f->next)
  397. if(f->nr == nr)
  398. return f;
  399. return 0;
  400. }
  401. int
  402. freefid(int nr)
  403. {
  404. Fid *f, **l;
  405. char buf[128];
  406. l = &fidhash(nr);
  407. for(f = *l; f; f = f->next) {
  408. if(f->nr == nr) {
  409. if(f->mid) {
  410. sprint(buf, "/mnt/exportfs/%d", f->mid);
  411. unmount(0, buf);
  412. psmap[f->mid] = 0;
  413. }
  414. if(f->f) {
  415. freefile(f->f);
  416. f->f = nil;
  417. }
  418. if(f->dir){
  419. free(f->dir);
  420. f->dir = nil;
  421. }
  422. *l = f->next;
  423. f->next = fidfree;
  424. fidfree = f;
  425. return 1;
  426. }
  427. l = &f->next;
  428. }
  429. return 0;
  430. }
  431. Fid *
  432. newfid(int nr)
  433. {
  434. Fid *new, **l;
  435. int i;
  436. l = &fidhash(nr);
  437. for(new = *l; new; new = new->next)
  438. if(new->nr == nr)
  439. return 0;
  440. if(fidfree == 0) {
  441. fidfree = emallocz(sizeof(Fid) * Fidchunk);
  442. for(i = 0; i < Fidchunk-1; i++)
  443. fidfree[i].next = &fidfree[i+1];
  444. fidfree[Fidchunk-1].next = 0;
  445. }
  446. new = fidfree;
  447. fidfree = new->next;
  448. memset(new, 0, sizeof(Fid));
  449. new->next = *l;
  450. *l = new;
  451. new->nr = nr;
  452. new->fid = -1;
  453. new->mid = 0;
  454. return new;
  455. }
  456. Fsrpc *
  457. getsbuf(void)
  458. {
  459. static int ap;
  460. int look, rounds;
  461. Fsrpc *wb;
  462. int small_instead_of_fast = 1;
  463. if(small_instead_of_fast)
  464. ap = 0; /* so we always start looking at the beginning and reuse buffers */
  465. for(rounds = 0; rounds < 10; rounds++) {
  466. for(look = 0; look < Nr_workbufs; look++) {
  467. if(++ap == Nr_workbufs)
  468. ap = 0;
  469. if(Workq[ap].busy == 0)
  470. break;
  471. }
  472. if(look == Nr_workbufs){
  473. sleep(10 * rounds);
  474. continue;
  475. }
  476. wb = &Workq[ap];
  477. wb->pid = 0;
  478. wb->canint = 0;
  479. wb->flushtag = NOTAG;
  480. wb->busy = 1;
  481. if(wb->buf == nil) /* allocate buffers dynamically to keep size down */
  482. wb->buf = emallocz(messagesize);
  483. return wb;
  484. }
  485. fatal("No more work buffers");
  486. return nil;
  487. }
  488. void
  489. freefile(File *f)
  490. {
  491. File *parent, *child;
  492. Loop:
  493. f->ref--;
  494. if(f->ref > 0)
  495. return;
  496. freecnt++;
  497. if(f->ref < 0) abort();
  498. DEBUG(DFD, "free %s\n", f->name);
  499. /* delete from parent */
  500. parent = f->parent;
  501. if(parent->child == f)
  502. parent->child = f->childlist;
  503. else{
  504. for(child=parent->child; child->childlist!=f; child=child->childlist)
  505. if(child->childlist == nil)
  506. fatal("bad child list");
  507. child->childlist = f->childlist;
  508. }
  509. freeqid(f->qidt);
  510. free(f->name);
  511. f->name = nil;
  512. free(f);
  513. f = parent;
  514. if(f != nil)
  515. goto Loop;
  516. }
  517. File *
  518. file(File *parent, char *name)
  519. {
  520. Dir *dir;
  521. char *path;
  522. File *f;
  523. DEBUG(DFD, "\tfile: 0x%p %s name %s\n", parent, parent->name, name);
  524. path = makepath(parent, name);
  525. if(patternfile != nil && excludefile(path)){
  526. free(path);
  527. return nil;
  528. }
  529. dir = dirstat(path);
  530. free(path);
  531. if(dir == nil)
  532. return nil;
  533. for(f = parent->child; f; f = f->childlist)
  534. if(strcmp(name, f->name) == 0)
  535. break;
  536. if(f == nil){
  537. f = emallocz(sizeof(File));
  538. f->name = estrdup(name);
  539. f->parent = parent;
  540. f->childlist = parent->child;
  541. parent->child = f;
  542. parent->ref++;
  543. f->ref = 0;
  544. filecnt++;
  545. }
  546. f->ref++;
  547. f->qid.type = dir->qid.type;
  548. f->qid.vers = dir->qid.vers;
  549. f->qidt = uniqueqid(dir);
  550. f->qid.path = f->qidt->uniqpath;
  551. f->inval = 0;
  552. free(dir);
  553. return f;
  554. }
  555. void
  556. initroot(void)
  557. {
  558. Dir *dir;
  559. root = emallocz(sizeof(File));
  560. root->name = estrdup(".");
  561. dir = dirstat(root->name);
  562. if(dir == nil)
  563. fatal("root stat");
  564. root->ref = 1;
  565. root->qid.vers = dir->qid.vers;
  566. root->qidt = uniqueqid(dir);
  567. root->qid.path = root->qidt->uniqpath;
  568. root->qid.type = QTDIR;
  569. free(dir);
  570. psmpt = emallocz(sizeof(File));
  571. psmpt->name = estrdup("/");
  572. dir = dirstat(psmpt->name);
  573. if(dir == nil)
  574. return;
  575. psmpt->ref = 1;
  576. psmpt->qid.vers = dir->qid.vers;
  577. psmpt->qidt = uniqueqid(dir);
  578. psmpt->qid.path = psmpt->qidt->uniqpath;
  579. free(dir);
  580. psmpt = file(psmpt, "mnt");
  581. if(psmpt == 0)
  582. return;
  583. psmpt = file(psmpt, "exportfs");
  584. }
  585. char*
  586. makepath(File *p, char *name)
  587. {
  588. int i, n;
  589. char *c, *s, *path, *seg[256];
  590. seg[0] = name;
  591. n = strlen(name)+2;
  592. for(i = 1; i < 256 && p; i++, p = p->parent){
  593. seg[i] = p->name;
  594. n += strlen(p->name)+1;
  595. }
  596. path = malloc(n);
  597. if(path == nil)
  598. fatal("out of memory");
  599. s = path;
  600. while(i--) {
  601. for(c = seg[i]; *c; c++)
  602. *s++ = *c;
  603. *s++ = '/';
  604. }
  605. while(s[-1] == '/')
  606. s--;
  607. *s = '\0';
  608. return path;
  609. }
  610. int
  611. qidhash(vlong path)
  612. {
  613. int h, n;
  614. h = 0;
  615. for(n=0; n<64; n+=Nqidbits){
  616. h ^= path;
  617. path >>= Nqidbits;
  618. }
  619. return h & (Nqidtab-1);
  620. }
  621. void
  622. freeqid(Qidtab *q)
  623. {
  624. ulong h;
  625. Qidtab *l;
  626. q->ref--;
  627. if(q->ref > 0)
  628. return;
  629. qfreecnt++;
  630. h = qidhash(q->path);
  631. if(qidtab[h] == q)
  632. qidtab[h] = q->next;
  633. else{
  634. for(l=qidtab[h]; l->next!=q; l=l->next)
  635. if(l->next == nil)
  636. fatal("bad qid list");
  637. l->next = q->next;
  638. }
  639. free(q);
  640. }
  641. Qidtab*
  642. qidlookup(Dir *d)
  643. {
  644. ulong h;
  645. Qidtab *q;
  646. h = qidhash(d->qid.path);
  647. for(q=qidtab[h]; q!=nil; q=q->next)
  648. if(q->type==d->type && q->dev==d->dev && q->path==d->qid.path)
  649. return q;
  650. return nil;
  651. }
  652. int
  653. qidexists(vlong path)
  654. {
  655. int h;
  656. Qidtab *q;
  657. for(h=0; h<Nqidtab; h++)
  658. for(q=qidtab[h]; q!=nil; q=q->next)
  659. if(q->uniqpath == path)
  660. return 1;
  661. return 0;
  662. }
  663. Qidtab*
  664. uniqueqid(Dir *d)
  665. {
  666. ulong h;
  667. vlong path;
  668. Qidtab *q;
  669. q = qidlookup(d);
  670. if(q != nil){
  671. q->ref++;
  672. return q;
  673. }
  674. path = d->qid.path;
  675. while(qidexists(path)){
  676. DEBUG(DFD, "collision on %s\n", d->name);
  677. /* collision: find a new one */
  678. ncollision++;
  679. path &= QIDPATH;
  680. ++newqid;
  681. if(newqid >= (1<<16)){
  682. DEBUG(DFD, "collision wraparound\n");
  683. newqid = 1;
  684. }
  685. path |= newqid<<48;
  686. DEBUG(DFD, "assign qid %.16llux\n", path);
  687. }
  688. q = mallocz(sizeof(Qidtab), 1);
  689. if(q == nil)
  690. fatal("no memory for qid table");
  691. qidcnt++;
  692. q->ref = 1;
  693. q->type = d->type;
  694. q->dev = d->dev;
  695. q->path = d->qid.path;
  696. q->uniqpath = path;
  697. h = qidhash(d->qid.path);
  698. q->next = qidtab[h];
  699. qidtab[h] = q;
  700. return q;
  701. }
  702. void
  703. fatal(char *s, ...)
  704. {
  705. char buf[ERRMAX];
  706. va_list arg;
  707. Proc *m;
  708. if (s) {
  709. va_start(arg, s);
  710. vsnprint(buf, ERRMAX, s, arg);
  711. va_end(arg);
  712. }
  713. /* Clear away the slave children */
  714. for(m = Proclist; m; m = m->next)
  715. postnote(PNPROC, m->pid, "kill");
  716. DEBUG(DFD, "%s\n", buf);
  717. if (s)
  718. sysfatal("%s", buf); /* caution: buf could contain '%' */
  719. else
  720. exits(nil);
  721. }
  722. void*
  723. emallocz(uint n)
  724. {
  725. void *p;
  726. p = mallocz(n, 1);
  727. if(p == nil)
  728. fatal(Enomem);
  729. return p;
  730. }
  731. char*
  732. estrdup(char *s)
  733. {
  734. char *t;
  735. t = strdup(s);
  736. if(t == nil)
  737. fatal(Enomem);
  738. return t;
  739. }
  740. /* Network on fd1, mount driver on fd0 */
  741. int
  742. filter(int fd, char *cmd)
  743. {
  744. int p[2], lfd, len, nb, argc;
  745. char newport[128], buf[128], devdir[40], *s, *file, *argv[16];
  746. /* Get a free port and post it to the client. */
  747. if (announce(anstring, devdir) < 0)
  748. sysfatal("filter: Cannot announce %s: %r", anstring);
  749. snprint(buf, sizeof(buf), "%s/local", devdir);
  750. buf[sizeof buf - 1] = '\0';
  751. if ((lfd = open(buf, OREAD)) < 0)
  752. sysfatal("filter: Cannot open %s: %r", buf);
  753. if ((len = read(lfd, newport, sizeof newport - 1)) < 0)
  754. sysfatal("filter: Cannot read %s: %r", buf);
  755. close(lfd);
  756. newport[len] = '\0';
  757. if ((s = strchr(newport, '\n')) != nil)
  758. *s = '\0';
  759. if ((nb = write(fd, newport, len)) < 0)
  760. sysfatal("getport; cannot write port; %r");
  761. assert(nb == len);
  762. argc = tokenize(cmd, argv, nelem(argv)-2);
  763. if (argc == 0)
  764. sysfatal("filter: empty command");
  765. argv[argc++] = buf;
  766. argv[argc] = nil;
  767. file = argv[0];
  768. if (s = strrchr(argv[0], '/'))
  769. argv[0] = s+1;
  770. if(pipe(p) < 0)
  771. fatal("pipe");
  772. switch(rfork(RFNOWAIT|RFPROC|RFFDG)) {
  773. case -1:
  774. fatal("rfork record module");
  775. case 0:
  776. if (dup(p[0], 1) < 0)
  777. fatal("filter: Cannot dup to 1; %r\n");
  778. if (dup(p[0], 0) < 0)
  779. fatal("filter: Cannot dup to 0; %r\n");
  780. close(p[0]);
  781. close(p[1]);
  782. exec(file, argv);
  783. fatal("exec record module");
  784. default:
  785. close(fd);
  786. close(p[0]);
  787. }
  788. return p[1];
  789. }
  790. static void
  791. mksecret(char *t, uchar *f)
  792. {
  793. sprint(t, "%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
  794. f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9]);
  795. }