exportfs.c 15 KB

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