fs.c 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651
  1. #include "common.h"
  2. #include <auth.h>
  3. #include <fcall.h>
  4. #include <libsec.h>
  5. #include <ctype.h>
  6. #include "dat.h"
  7. enum
  8. {
  9. OPERM = 0x3, // mask of all permission types in open mode
  10. };
  11. typedef struct Fid Fid;
  12. struct Fid
  13. {
  14. Qid qid;
  15. short busy;
  16. short open;
  17. int fid;
  18. Fid *next;
  19. Mailbox *mb;
  20. Message *m;
  21. Message *mtop; // top level message
  22. //finger pointers to speed up reads of large directories
  23. long foff; // offset/DIRLEN of finger
  24. Message *fptr; // pointer to message at off
  25. int fvers; // mailbox version when finger was saved
  26. };
  27. ulong path; // incremented for each new file
  28. Fid *fids;
  29. int mfd[2];
  30. char user[Elemlen];
  31. int messagesize = 4*1024*IOHDRSZ;
  32. uchar mdata[8*1024*IOHDRSZ];
  33. uchar mbuf[8*1024*IOHDRSZ];
  34. Fcall thdr;
  35. Fcall rhdr;
  36. int fflg;
  37. char *mntpt;
  38. int biffing;
  39. int plumbing = 1;
  40. QLock mbllock;
  41. Mailbox *mbl;
  42. Fid *newfid(int);
  43. void error(char*);
  44. void io(void);
  45. void *erealloc(void*, ulong);
  46. void *emalloc(ulong);
  47. void usage(void);
  48. void reader(void);
  49. int readheader(Message*, char*, int, int);
  50. int cistrncmp(char*, char*, int);
  51. int tokenconvert(String*, char*, int);
  52. String* stringconvert(String*, char*, int);
  53. void post(char*, char*, int);
  54. char *rflush(Fid*), *rauth(Fid*),
  55. *rattach(Fid*), *rwalk(Fid*),
  56. *ropen(Fid*), *rcreate(Fid*),
  57. *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
  58. *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*),
  59. *rversion(Fid*);
  60. char *(*fcalls[])(Fid*) = {
  61. [Tflush] rflush,
  62. [Tversion] rversion,
  63. [Tauth] rauth,
  64. [Tattach] rattach,
  65. [Twalk] rwalk,
  66. [Topen] ropen,
  67. [Tcreate] rcreate,
  68. [Tread] rread,
  69. [Twrite] rwrite,
  70. [Tclunk] rclunk,
  71. [Tremove] rremove,
  72. [Tstat] rstat,
  73. [Twstat] rwstat,
  74. };
  75. char Eperm[] = "permission denied";
  76. char Enotdir[] = "not a directory";
  77. char Enoauth[] = "upas/fs: authentication not required";
  78. char Enotexist[] = "file does not exist";
  79. char Einuse[] = "file in use";
  80. char Eexist[] = "file exists";
  81. char Enotowner[] = "not owner";
  82. char Eisopen[] = "file already open for I/O";
  83. char Excl[] = "exclusive use file already open";
  84. char Ename[] = "illegal name";
  85. char Ebadctl[] = "unknown control message";
  86. char *dirtab[] =
  87. {
  88. [Qdir] ".",
  89. [Qbody] "body",
  90. [Qbcc] "bcc",
  91. [Qcc] "cc",
  92. [Qdate] "date",
  93. [Qdigest] "digest",
  94. [Qdisposition] "disposition",
  95. [Qfilename] "filename",
  96. [Qfrom] "from",
  97. [Qheader] "header",
  98. [Qinfo] "info",
  99. [Qinreplyto] "inreplyto",
  100. [Qlines] "lines",
  101. [Qmimeheader] "mimeheader",
  102. [Qmessageid] "messageid",
  103. [Qraw] "raw",
  104. [Qrawunix] "rawunix",
  105. [Qrawbody] "rawbody",
  106. [Qrawheader] "rawheader",
  107. [Qreplyto] "replyto",
  108. [Qsender] "sender",
  109. [Qsubject] "subject",
  110. [Qto] "to",
  111. [Qtype] "type",
  112. [Qunixdate] "unixdate",
  113. [Qunixheader] "unixheader",
  114. [Qctl] "ctl",
  115. [Qmboxctl] "ctl",
  116. };
  117. enum
  118. {
  119. Hsize= 1277,
  120. };
  121. Hash *htab[Hsize];
  122. int debug;
  123. int fflag;
  124. int logging;
  125. void
  126. usage(void)
  127. {
  128. fprint(2, "usage: upas/fs [-bdlnps] [-f mboxfile] [-m mountpoint]\n");
  129. exits("usage");
  130. }
  131. void
  132. notifyf(void *a, char *s)
  133. {
  134. USED(a);
  135. if(strncmp(s, "interrupt", 9) == 0)
  136. noted(NCONT);
  137. noted(NDFLT);
  138. }
  139. void
  140. main(int argc, char *argv[])
  141. {
  142. int p[2], std, nodflt;
  143. char maildir[128];
  144. char mbox[128];
  145. char *mboxfile, *err;
  146. char srvfile[64];
  147. int srvpost;
  148. rfork(RFNOTEG);
  149. mntpt = nil;
  150. fflag = 0;
  151. mboxfile = nil;
  152. std = 0;
  153. nodflt = 0;
  154. srvpost = 0;
  155. ARGBEGIN{
  156. case 'b':
  157. biffing = 1;
  158. break;
  159. case 'f':
  160. fflag = 1;
  161. mboxfile = EARGF(usage());
  162. break;
  163. case 'm':
  164. mntpt = EARGF(usage());
  165. break;
  166. case 'd':
  167. debug = 1;
  168. break;
  169. case 'p':
  170. plumbing = 0;
  171. break;
  172. case 's':
  173. srvpost = 1;
  174. break;
  175. case 'l':
  176. logging = 1;
  177. break;
  178. case 'n':
  179. nodflt = 1;
  180. break;
  181. default:
  182. usage();
  183. }ARGEND
  184. if(argc)
  185. usage();
  186. if(pipe(p) < 0)
  187. error("pipe failed");
  188. mfd[0] = p[0];
  189. mfd[1] = p[0];
  190. notify(notifyf);
  191. strcpy(user, getuser());
  192. if(mntpt == nil){
  193. snprint(maildir, sizeof(maildir), "/mail/fs");
  194. mntpt = maildir;
  195. }
  196. if(mboxfile == nil && !nodflt){
  197. snprint(mbox, sizeof(mbox), "/mail/box/%s/mbox", user);
  198. mboxfile = mbox;
  199. std = 1;
  200. }
  201. if(debug)
  202. fmtinstall('F', fcallfmt);
  203. if(mboxfile != nil){
  204. err = newmbox(mboxfile, "mbox", std);
  205. if(err != nil)
  206. sysfatal("opening mailbox: %s", err);
  207. }
  208. switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG|RFREND)){
  209. case -1:
  210. error("fork");
  211. case 0:
  212. henter(PATH(0, Qtop), dirtab[Qctl],
  213. (Qid){PATH(0, Qctl), 0, QTFILE}, nil, nil);
  214. close(p[1]);
  215. io();
  216. postnote(PNGROUP, getpid(), "die yankee pig dog");
  217. break;
  218. default:
  219. close(p[0]); /* don't deadlock if child fails */
  220. if(srvpost){
  221. sprint(srvfile, "/srv/upasfs.%s", user);
  222. post(srvfile, "upasfs", p[1]);
  223. } else {
  224. if(mount(p[1], -1, mntpt, MREPL, "") < 0)
  225. error("mount failed");
  226. }
  227. }
  228. exits(0);
  229. }
  230. static int
  231. fileinfo(Message *m, int t, char **pp)
  232. {
  233. char *p;
  234. int len;
  235. p = "";
  236. len = 0;
  237. switch(t){
  238. case Qbody:
  239. p = m->body;
  240. len = m->bend - m->body;
  241. break;
  242. case Qbcc:
  243. if(m->bcc822){
  244. p = s_to_c(m->bcc822);
  245. len = strlen(p);
  246. }
  247. break;
  248. case Qcc:
  249. if(m->cc822){
  250. p = s_to_c(m->cc822);
  251. len = strlen(p);
  252. }
  253. break;
  254. case Qdisposition:
  255. switch(m->disposition){
  256. case Dinline:
  257. p = "inline";
  258. break;
  259. case Dfile:
  260. p = "file";
  261. break;
  262. }
  263. len = strlen(p);
  264. break;
  265. case Qdate:
  266. if(m->date822){
  267. p = s_to_c(m->date822);
  268. len = strlen(p);
  269. } else if(m->unixdate != nil){
  270. p = s_to_c(m->unixdate);
  271. len = strlen(p);
  272. }
  273. break;
  274. case Qfilename:
  275. if(m->filename){
  276. p = s_to_c(m->filename);
  277. len = strlen(p);
  278. }
  279. break;
  280. case Qinreplyto:
  281. if(m->inreplyto822){
  282. p = s_to_c(m->inreplyto822);
  283. len = strlen(p);
  284. }
  285. break;
  286. case Qmessageid:
  287. if(m->messageid822){
  288. p = s_to_c(m->messageid822);
  289. len = strlen(p);
  290. }
  291. break;
  292. case Qfrom:
  293. if(m->from822){
  294. p = s_to_c(m->from822);
  295. len = strlen(p);
  296. } else if(m->unixfrom != nil){
  297. p = s_to_c(m->unixfrom);
  298. len = strlen(p);
  299. }
  300. break;
  301. case Qheader:
  302. p = m->header;
  303. len = headerlen(m);
  304. break;
  305. case Qlines:
  306. p = m->lines;
  307. if(*p == 0)
  308. countlines(m);
  309. len = strlen(m->lines);
  310. break;
  311. case Qraw:
  312. p = m->start;
  313. if(strncmp(m->start, "From ", 5) == 0){
  314. p = strchr(p, '\n');
  315. if(p == nil)
  316. p = m->start;
  317. else
  318. p++;
  319. }
  320. len = m->end - p;
  321. break;
  322. case Qrawunix:
  323. p = m->start;
  324. len = m->end - p;
  325. break;
  326. case Qrawbody:
  327. p = m->rbody;
  328. len = m->rbend - p;
  329. break;
  330. case Qrawheader:
  331. p = m->header;
  332. len = m->hend - p;
  333. break;
  334. case Qmimeheader:
  335. p = m->mheader;
  336. len = m->mhend - p;
  337. break;
  338. case Qreplyto:
  339. p = nil;
  340. if(m->replyto822 != nil){
  341. p = s_to_c(m->replyto822);
  342. len = strlen(p);
  343. } else if(m->from822 != nil){
  344. p = s_to_c(m->from822);
  345. len = strlen(p);
  346. } else if(m->sender822 != nil){
  347. p = s_to_c(m->sender822);
  348. len = strlen(p);
  349. } else if(m->unixfrom != nil){
  350. p = s_to_c(m->unixfrom);
  351. len = strlen(p);
  352. }
  353. break;
  354. case Qsender:
  355. if(m->sender822){
  356. p = s_to_c(m->sender822);
  357. len = strlen(p);
  358. }
  359. break;
  360. case Qsubject:
  361. p = nil;
  362. if(m->subject822){
  363. p = s_to_c(m->subject822);
  364. len = strlen(p);
  365. }
  366. break;
  367. case Qto:
  368. if(m->to822){
  369. p = s_to_c(m->to822);
  370. len = strlen(p);
  371. }
  372. break;
  373. case Qtype:
  374. if(m->type){
  375. p = s_to_c(m->type);
  376. len = strlen(p);
  377. }
  378. break;
  379. case Qunixdate:
  380. if(m->unixdate){
  381. p = s_to_c(m->unixdate);
  382. len = strlen(p);
  383. }
  384. break;
  385. case Qunixheader:
  386. if(m->unixheader){
  387. p = s_to_c(m->unixheader);
  388. len = s_len(m->unixheader);
  389. }
  390. break;
  391. case Qdigest:
  392. if(m->sdigest){
  393. p = s_to_c(m->sdigest);
  394. len = strlen(p);
  395. }
  396. break;
  397. }
  398. *pp = p;
  399. return len;
  400. }
  401. int infofields[] = {
  402. Qfrom,
  403. Qto,
  404. Qcc,
  405. Qreplyto,
  406. Qunixdate,
  407. Qsubject,
  408. Qtype,
  409. Qdisposition,
  410. Qfilename,
  411. Qdigest,
  412. Qbcc,
  413. Qinreplyto,
  414. Qdate,
  415. Qsender,
  416. Qmessageid,
  417. Qlines,
  418. -1,
  419. };
  420. static int
  421. readinfo(Message *m, char *buf, long off, int count)
  422. {
  423. char *p;
  424. int len, i, n;
  425. String *s;
  426. s = s_new();
  427. len = 0;
  428. for(i = 0; len < count && infofields[i] >= 0; i++){
  429. n = fileinfo(m, infofields[i], &p);
  430. s = stringconvert(s, p, n);
  431. s_append(s, "\n");
  432. p = s_to_c(s);
  433. n = strlen(p);
  434. if(off > 0){
  435. if(off >= n){
  436. off -= n;
  437. continue;
  438. }
  439. p += off;
  440. n -= off;
  441. off = 0;
  442. }
  443. if(n > count - len)
  444. n = count - len;
  445. if(buf)
  446. memmove(buf+len, p, n);
  447. len += n;
  448. }
  449. s_free(s);
  450. return len;
  451. }
  452. static void
  453. mkstat(Dir *d, Mailbox *mb, Message *m, int t)
  454. {
  455. char *p;
  456. d->uid = user;
  457. d->gid = user;
  458. d->muid = user;
  459. d->mode = 0444;
  460. d->qid.vers = 0;
  461. d->qid.type = QTFILE;
  462. d->type = 0;
  463. d->dev = 0;
  464. if(mb != nil && mb->d != nil){
  465. d->atime = mb->d->atime;
  466. d->mtime = mb->d->mtime;
  467. } else {
  468. d->atime = time(0);
  469. d->mtime = d->atime;
  470. }
  471. switch(t){
  472. case Qtop:
  473. d->name = ".";
  474. d->mode = DMDIR|0555;
  475. d->atime = d->mtime = time(0);
  476. d->length = 0;
  477. d->qid.path = PATH(0, Qtop);
  478. d->qid.type = QTDIR;
  479. break;
  480. case Qmbox:
  481. d->name = mb->name;
  482. d->mode = DMDIR|0555;
  483. d->length = 0;
  484. d->qid.path = PATH(mb->id, Qmbox);
  485. d->qid.type = QTDIR;
  486. d->qid.vers = mb->vers;
  487. break;
  488. case Qdir:
  489. d->name = m->name;
  490. d->mode = DMDIR|0555;
  491. d->length = 0;
  492. d->qid.path = PATH(m->id, Qdir);
  493. d->qid.type = QTDIR;
  494. break;
  495. case Qctl:
  496. d->name = dirtab[t];
  497. d->mode = 0666;
  498. d->atime = d->mtime = time(0);
  499. d->length = 0;
  500. d->qid.path = PATH(0, Qctl);
  501. break;
  502. case Qmboxctl:
  503. d->name = dirtab[t];
  504. d->mode = 0222;
  505. d->atime = d->mtime = time(0);
  506. d->length = 0;
  507. d->qid.path = PATH(mb->id, Qmboxctl);
  508. break;
  509. case Qinfo:
  510. d->name = dirtab[t];
  511. d->length = readinfo(m, nil, 0, 1<<30);
  512. d->qid.path = PATH(m->id, t);
  513. break;
  514. default:
  515. d->name = dirtab[t];
  516. d->length = fileinfo(m, t, &p);
  517. d->qid.path = PATH(m->id, t);
  518. break;
  519. }
  520. }
  521. char*
  522. rversion(Fid*)
  523. {
  524. Fid *f;
  525. if(thdr.msize < 256)
  526. return "max messagesize too small";
  527. if(thdr.msize < messagesize)
  528. messagesize = thdr.msize;
  529. rhdr.msize = messagesize;
  530. if(strncmp(thdr.version, "9P2000", 6) != 0)
  531. return "unknown 9P version";
  532. else
  533. rhdr.version = "9P2000";
  534. for(f = fids; f; f = f->next)
  535. if(f->busy)
  536. rclunk(f);
  537. return nil;
  538. }
  539. char*
  540. rauth(Fid*)
  541. {
  542. return Enoauth;
  543. }
  544. char*
  545. rflush(Fid *f)
  546. {
  547. USED(f);
  548. return 0;
  549. }
  550. char*
  551. rattach(Fid *f)
  552. {
  553. f->busy = 1;
  554. f->m = nil;
  555. f->mb = nil;
  556. f->qid.path = PATH(0, Qtop);
  557. f->qid.type = QTDIR;
  558. f->qid.vers = 0;
  559. rhdr.qid = f->qid;
  560. if(strcmp(thdr.uname, user) != 0)
  561. return Eperm;
  562. return 0;
  563. }
  564. static Fid*
  565. doclone(Fid *f, int nfid)
  566. {
  567. Fid *nf;
  568. nf = newfid(nfid);
  569. if(nf->busy)
  570. return nil;
  571. nf->busy = 1;
  572. nf->open = 0;
  573. nf->m = f->m;
  574. nf->mtop = f->mtop;
  575. nf->mb = f->mb;
  576. if(f->mb != nil)
  577. mboxincref(f->mb);
  578. if(f->mtop != nil){
  579. qlock(f->mb);
  580. msgincref(f->mtop);
  581. qunlock(f->mb);
  582. }
  583. nf->qid = f->qid;
  584. return nf;
  585. }
  586. char*
  587. dowalk(Fid *f, char *name)
  588. {
  589. int t;
  590. Mailbox *omb, *mb;
  591. char *rv, *p;
  592. Hash *h;
  593. t = FILE(f->qid.path);
  594. rv = Enotexist;
  595. omb = f->mb;
  596. if(omb)
  597. qlock(omb);
  598. else
  599. qlock(&mbllock);
  600. // this must catch everything except . and ..
  601. retry:
  602. h = hlook(f->qid.path, name);
  603. if(h != nil){
  604. f->mb = h->mb;
  605. f->m = h->m;
  606. switch(t){
  607. case Qtop:
  608. if(f->mb != nil)
  609. mboxincref(f->mb);
  610. break;
  611. case Qmbox:
  612. if(f->m){
  613. msgincref(f->m);
  614. f->mtop = f->m;
  615. }
  616. break;
  617. }
  618. f->qid = h->qid;
  619. rv = nil;
  620. } else if((p = strchr(name, '.')) != nil && *name != '.'){
  621. *p = 0;
  622. goto retry;
  623. }
  624. if(omb)
  625. qunlock(omb);
  626. else
  627. qunlock(&mbllock);
  628. if(rv == nil)
  629. return rv;
  630. if(strcmp(name, ".") == 0)
  631. return nil;
  632. if(f->qid.type != QTDIR)
  633. return Enotdir;
  634. if(strcmp(name, "..") == 0){
  635. switch(t){
  636. case Qtop:
  637. f->qid.path = PATH(0, Qtop);
  638. f->qid.type = QTDIR;
  639. f->qid.vers = 0;
  640. break;
  641. case Qmbox:
  642. f->qid.path = PATH(0, Qtop);
  643. f->qid.type = QTDIR;
  644. f->qid.vers = 0;
  645. qlock(&mbllock);
  646. mb = f->mb;
  647. f->mb = nil;
  648. mboxdecref(mb);
  649. qunlock(&mbllock);
  650. break;
  651. case Qdir:
  652. qlock(f->mb);
  653. if(f->m->whole == f->mb->root){
  654. f->qid.path = PATH(f->mb->id, Qmbox);
  655. f->qid.type = QTDIR;
  656. f->qid.vers = f->mb->d->qid.vers;
  657. msgdecref(f->mb, f->mtop);
  658. f->m = f->mtop = nil;
  659. } else {
  660. f->m = f->m->whole;
  661. f->qid.path = PATH(f->m->id, Qdir);
  662. f->qid.type = QTDIR;
  663. }
  664. qunlock(f->mb);
  665. break;
  666. }
  667. rv = nil;
  668. }
  669. return rv;
  670. }
  671. char*
  672. rwalk(Fid *f)
  673. {
  674. Fid *nf;
  675. char *rv;
  676. int i;
  677. if(f->open)
  678. return Eisopen;
  679. rhdr.nwqid = 0;
  680. nf = nil;
  681. /* clone if requested */
  682. if(thdr.newfid != thdr.fid){
  683. nf = doclone(f, thdr.newfid);
  684. if(nf == nil)
  685. return "new fid in use";
  686. f = nf;
  687. }
  688. /* if it's just a clone, return */
  689. if(thdr.nwname == 0 && nf != nil)
  690. return nil;
  691. /* walk each element */
  692. rv = nil;
  693. for(i = 0; i < thdr.nwname; i++){
  694. rv = dowalk(f, thdr.wname[i]);
  695. if(rv != nil){
  696. if(nf != nil)
  697. rclunk(nf);
  698. break;
  699. }
  700. rhdr.wqid[i] = f->qid;
  701. }
  702. rhdr.nwqid = i;
  703. /* we only error out if no walk */
  704. if(i > 0)
  705. rv = nil;
  706. return rv;
  707. }
  708. char *
  709. ropen(Fid *f)
  710. {
  711. int file;
  712. if(f->open)
  713. return Eisopen;
  714. file = FILE(f->qid.path);
  715. if(thdr.mode != OREAD)
  716. if(file != Qctl && file != Qmboxctl)
  717. return Eperm;
  718. // make sure we've decoded
  719. if(file == Qbody){
  720. if(f->m->decoded == 0)
  721. decode(f->m);
  722. if(f->m->converted == 0)
  723. convert(f->m);
  724. }
  725. rhdr.iounit = 0;
  726. rhdr.qid = f->qid;
  727. f->open = 1;
  728. return 0;
  729. }
  730. char *
  731. rcreate(Fid*)
  732. {
  733. return Eperm;
  734. }
  735. int
  736. readtopdir(Fid*, uchar *buf, long off, int cnt, int blen)
  737. {
  738. Dir d;
  739. int m, n;
  740. long pos;
  741. Mailbox *mb;
  742. n = 0;
  743. pos = 0;
  744. mkstat(&d, nil, nil, Qctl);
  745. m = convD2M(&d, &buf[n], blen);
  746. if(off <= pos){
  747. if(m <= BIT16SZ || m > cnt)
  748. return 0;
  749. n += m;
  750. cnt -= m;
  751. }
  752. pos += m;
  753. for(mb = mbl; mb != nil; mb = mb->next){
  754. mkstat(&d, mb, nil, Qmbox);
  755. m = convD2M(&d, &buf[n], blen-n);
  756. if(off <= pos){
  757. if(m <= BIT16SZ || m > cnt)
  758. break;
  759. n += m;
  760. cnt -= m;
  761. }
  762. pos += m;
  763. }
  764. return n;
  765. }
  766. int
  767. readmboxdir(Fid *f, uchar *buf, long off, int cnt, int blen)
  768. {
  769. Dir d;
  770. int n, m;
  771. long pos;
  772. Message *msg;
  773. n = 0;
  774. if(f->mb->ctl){
  775. mkstat(&d, f->mb, nil, Qmboxctl);
  776. m = convD2M(&d, &buf[n], blen);
  777. if(off == 0){
  778. if(m <= BIT16SZ || m > cnt){
  779. f->fptr = nil;
  780. return 0;
  781. }
  782. n += m;
  783. cnt -= m;
  784. } else
  785. off -= m;
  786. }
  787. // to avoid n**2 reads of the directory, use a saved finger pointer
  788. if(f->mb->vers == f->fvers && off >= f->foff && f->fptr != nil){
  789. msg = f->fptr;
  790. pos = f->foff;
  791. } else {
  792. msg = f->mb->root->part;
  793. pos = 0;
  794. }
  795. for(; cnt > 0 && msg != nil; msg = msg->next){
  796. // act like deleted files aren't there
  797. if(msg->deleted)
  798. continue;
  799. mkstat(&d, f->mb, msg, Qdir);
  800. m = convD2M(&d, &buf[n], blen-n);
  801. if(off <= pos){
  802. if(m <= BIT16SZ || m > cnt)
  803. break;
  804. n += m;
  805. cnt -= m;
  806. }
  807. pos += m;
  808. }
  809. // save a finger pointer for next read of the mbox directory
  810. f->foff = pos;
  811. f->fptr = msg;
  812. f->fvers = f->mb->vers;
  813. return n;
  814. }
  815. int
  816. readmsgdir(Fid *f, uchar *buf, long off, int cnt, int blen)
  817. {
  818. Dir d;
  819. int i, n, m;
  820. long pos;
  821. Message *msg;
  822. n = 0;
  823. pos = 0;
  824. for(i = 0; i < Qmax; i++){
  825. mkstat(&d, f->mb, f->m, i);
  826. m = convD2M(&d, &buf[n], blen-n);
  827. if(off <= pos){
  828. if(m <= BIT16SZ || m > cnt)
  829. return n;
  830. n += m;
  831. cnt -= m;
  832. }
  833. pos += m;
  834. }
  835. for(msg = f->m->part; msg != nil; msg = msg->next){
  836. mkstat(&d, f->mb, msg, Qdir);
  837. m = convD2M(&d, &buf[n], blen-n);
  838. if(off <= pos){
  839. if(m <= BIT16SZ || m > cnt)
  840. break;
  841. n += m;
  842. cnt -= m;
  843. }
  844. pos += m;
  845. }
  846. return n;
  847. }
  848. char*
  849. rread(Fid *f)
  850. {
  851. long off;
  852. int t, i, n, cnt;
  853. char *p;
  854. rhdr.count = 0;
  855. off = thdr.offset;
  856. cnt = thdr.count;
  857. if(cnt > messagesize - IOHDRSZ)
  858. cnt = messagesize - IOHDRSZ;
  859. rhdr.data = (char*)mbuf;
  860. t = FILE(f->qid.path);
  861. if(f->qid.type & QTDIR){
  862. if(t == Qtop) {
  863. qlock(&mbllock);
  864. n = readtopdir(f, mbuf, off, cnt, messagesize - IOHDRSZ);
  865. qunlock(&mbllock);
  866. } else if(t == Qmbox) {
  867. qlock(f->mb);
  868. if(off == 0)
  869. syncmbox(f->mb, 1);
  870. n = readmboxdir(f, mbuf, off, cnt, messagesize - IOHDRSZ);
  871. qunlock(f->mb);
  872. } else if(t == Qmboxctl) {
  873. n = 0;
  874. } else {
  875. n = readmsgdir(f, mbuf, off, cnt, messagesize - IOHDRSZ);
  876. }
  877. rhdr.count = n;
  878. return nil;
  879. }
  880. if(FILE(f->qid.path) == Qheader){
  881. rhdr.count = readheader(f->m, (char*)mbuf, off, cnt);
  882. return nil;
  883. }
  884. if(FILE(f->qid.path) == Qinfo){
  885. rhdr.count = readinfo(f->m, (char*)mbuf, off, cnt);
  886. return nil;
  887. }
  888. i = fileinfo(f->m, FILE(f->qid.path), &p);
  889. if(off < i){
  890. if((off + cnt) > i)
  891. cnt = i - off;
  892. memmove(mbuf, p + off, cnt);
  893. rhdr.count = cnt;
  894. }
  895. return nil;
  896. }
  897. char*
  898. rwrite(Fid *f)
  899. {
  900. char *err;
  901. char *token[1024];
  902. int t, n;
  903. String *file;
  904. t = FILE(f->qid.path);
  905. rhdr.count = thdr.count;
  906. switch(t){
  907. case Qctl:
  908. if(thdr.count == 0)
  909. return Ebadctl;
  910. if(thdr.data[thdr.count-1] == '\n')
  911. thdr.data[thdr.count-1] = 0;
  912. else
  913. thdr.data[thdr.count] = 0;
  914. n = tokenize(thdr.data, token, nelem(token));
  915. if(n == 0)
  916. return Ebadctl;
  917. if(strcmp(token[0], "open") == 0){
  918. file = s_new();
  919. switch(n){
  920. case 1:
  921. err = Ebadctl;
  922. break;
  923. case 2:
  924. mboxpath(token[1], getlog(), file, 0);
  925. err = newmbox(s_to_c(file), nil, 0);
  926. break;
  927. default:
  928. mboxpath(token[1], getlog(), file, 0);
  929. if(strchr(token[2], '/') != nil)
  930. err = "/ not allowed in mailbox name";
  931. else
  932. err = newmbox(s_to_c(file), token[2], 0);
  933. break;
  934. }
  935. s_free(file);
  936. return err;
  937. }
  938. if(strcmp(token[0], "close") == 0){
  939. if(n < 2)
  940. return nil;
  941. freembox(token[1]);
  942. return nil;
  943. }
  944. if(strcmp(token[0], "delete") == 0){
  945. if(n < 3)
  946. return nil;
  947. delmessages(n-1, &token[1]);
  948. return nil;
  949. }
  950. return Ebadctl;
  951. case Qmboxctl:
  952. if(f->mb && f->mb->ctl){
  953. if(thdr.count == 0)
  954. return Ebadctl;
  955. if(thdr.data[thdr.count-1] == '\n')
  956. thdr.data[thdr.count-1] = 0;
  957. else
  958. thdr.data[thdr.count] = 0;
  959. n = tokenize(thdr.data, token, nelem(token));
  960. if(n == 0)
  961. return Ebadctl;
  962. return (*f->mb->ctl)(f->mb, n, token);
  963. }
  964. }
  965. return Eperm;
  966. }
  967. char *
  968. rclunk(Fid *f)
  969. {
  970. Mailbox *mb;
  971. f->busy = 0;
  972. f->open = 0;
  973. if(f->mtop != nil){
  974. qlock(f->mb);
  975. msgdecref(f->mb, f->mtop);
  976. qunlock(f->mb);
  977. }
  978. f->m = f->mtop = nil;
  979. mb = f->mb;
  980. if(mb != nil){
  981. f->mb = nil;
  982. assert(mb->refs > 0);
  983. qlock(&mbllock);
  984. mboxdecref(mb);
  985. qunlock(&mbllock);
  986. }
  987. f->fid = -1;
  988. return 0;
  989. }
  990. char *
  991. rremove(Fid *f)
  992. {
  993. if(f->m != nil){
  994. if(f->m->deleted == 0)
  995. mailplumb(f->mb, f->m, 1);
  996. f->m->deleted = 1;
  997. }
  998. return rclunk(f);
  999. }
  1000. char *
  1001. rstat(Fid *f)
  1002. {
  1003. Dir d;
  1004. if(FILE(f->qid.path) == Qmbox){
  1005. qlock(f->mb);
  1006. syncmbox(f->mb, 1);
  1007. qunlock(f->mb);
  1008. }
  1009. mkstat(&d, f->mb, f->m, FILE(f->qid.path));
  1010. rhdr.nstat = convD2M(&d, mbuf, messagesize - IOHDRSZ);
  1011. rhdr.stat = mbuf;
  1012. return 0;
  1013. }
  1014. char *
  1015. rwstat(Fid*)
  1016. {
  1017. return Eperm;
  1018. }
  1019. Fid *
  1020. newfid(int fid)
  1021. {
  1022. Fid *f, *ff;
  1023. ff = 0;
  1024. for(f = fids; f; f = f->next)
  1025. if(f->fid == fid)
  1026. return f;
  1027. else if(!ff && !f->busy)
  1028. ff = f;
  1029. if(ff){
  1030. ff->fid = fid;
  1031. ff->fptr = nil;
  1032. return ff;
  1033. }
  1034. f = emalloc(sizeof *f);
  1035. f->fid = fid;
  1036. f->fptr = nil;
  1037. f->next = fids;
  1038. fids = f;
  1039. return f;
  1040. }
  1041. int
  1042. fidmboxrefs(Mailbox *mb)
  1043. {
  1044. Fid *f;
  1045. int refs = 0;
  1046. for(f = fids; f; f = f->next){
  1047. if(f->mb == mb)
  1048. refs++;
  1049. }
  1050. return refs;
  1051. }
  1052. void
  1053. io(void)
  1054. {
  1055. char *err;
  1056. int n;
  1057. /* start a process to watch the mailboxes*/
  1058. if(plumbing){
  1059. switch(rfork(RFPROC|RFMEM)){
  1060. case -1:
  1061. /* oh well */
  1062. break;
  1063. case 0:
  1064. reader();
  1065. exits(nil);
  1066. default:
  1067. break;
  1068. }
  1069. }
  1070. for(;;){
  1071. /*
  1072. * reading from a pipe or a network device
  1073. * will give an error after a few eof reads
  1074. * however, we cannot tell the difference
  1075. * between a zero-length read and an interrupt
  1076. * on the processes writing to us,
  1077. * so we wait for the error
  1078. */
  1079. checkmboxrefs();
  1080. n = read9pmsg(mfd[0], mdata, messagesize);
  1081. if(n == 0)
  1082. continue;
  1083. if(n < 0)
  1084. return;
  1085. if(convM2S(mdata, n, &thdr) == 0)
  1086. continue;
  1087. if(debug)
  1088. fprint(2, "%s:<-%F\n", argv0, &thdr);
  1089. rhdr.data = (char*)mdata + messagesize;
  1090. if(!fcalls[thdr.type])
  1091. err = "bad fcall type";
  1092. else
  1093. err = (*fcalls[thdr.type])(newfid(thdr.fid));
  1094. if(err){
  1095. rhdr.type = Rerror;
  1096. rhdr.ename = err;
  1097. }else{
  1098. rhdr.type = thdr.type + 1;
  1099. rhdr.fid = thdr.fid;
  1100. }
  1101. rhdr.tag = thdr.tag;
  1102. if(debug)
  1103. fprint(2, "%s:->%F\n", argv0, &rhdr);/**/
  1104. n = convS2M(&rhdr, mdata, messagesize);
  1105. if(write(mfd[1], mdata, n) != n)
  1106. error("mount write");
  1107. }
  1108. }
  1109. void
  1110. reader(void)
  1111. {
  1112. ulong t;
  1113. Dir *d;
  1114. Mailbox *mb;
  1115. sleep(15*1000);
  1116. for(;;){
  1117. t = time(0);
  1118. qlock(&mbllock);
  1119. for(mb = mbl; mb != nil; mb = mb->next){
  1120. assert(mb->refs > 0);
  1121. if(mb->waketime != 0 && t > mb->waketime){
  1122. qlock(mb);
  1123. mb->waketime = 0;
  1124. break;
  1125. }
  1126. d = dirstat(mb->path);
  1127. if(d == nil)
  1128. continue;
  1129. qlock(mb);
  1130. if(mb->d)
  1131. if(d->qid.path != mb->d->qid.path
  1132. || d->qid.vers != mb->d->qid.vers){
  1133. free(d);
  1134. break;
  1135. }
  1136. qunlock(mb);
  1137. free(d);
  1138. }
  1139. qunlock(&mbllock);
  1140. if(mb != nil){
  1141. syncmbox(mb, 1);
  1142. qunlock(mb);
  1143. } else
  1144. sleep(15*1000);
  1145. }
  1146. }
  1147. int
  1148. newid(void)
  1149. {
  1150. int rv;
  1151. static int id;
  1152. static Lock idlock;
  1153. lock(&idlock);
  1154. rv = ++id;
  1155. unlock(&idlock);
  1156. return rv;
  1157. }
  1158. void
  1159. error(char *s)
  1160. {
  1161. postnote(PNGROUP, getpid(), "die yankee pig dog");
  1162. fprint(2, "%s: %s: %r\n", argv0, s);
  1163. exits(s);
  1164. }
  1165. typedef struct Ignorance Ignorance;
  1166. struct Ignorance
  1167. {
  1168. Ignorance *next;
  1169. char *str; /* string */
  1170. int partial; /* true if not exact match */
  1171. };
  1172. Ignorance *ignorance;
  1173. /*
  1174. * read the file of headers to ignore
  1175. */
  1176. void
  1177. readignore(void)
  1178. {
  1179. char *p;
  1180. Ignorance *i;
  1181. Biobuf *b;
  1182. if(ignorance != nil)
  1183. return;
  1184. b = Bopen("/mail/lib/ignore", OREAD);
  1185. if(b == 0)
  1186. return;
  1187. while(p = Brdline(b, '\n')){
  1188. p[Blinelen(b)-1] = 0;
  1189. while(*p && (*p == ' ' || *p == '\t'))
  1190. p++;
  1191. if(*p == '#')
  1192. continue;
  1193. i = malloc(sizeof(Ignorance));
  1194. if(i == 0)
  1195. break;
  1196. i->partial = strlen(p);
  1197. i->str = strdup(p);
  1198. if(i->str == 0){
  1199. free(i);
  1200. break;
  1201. }
  1202. i->next = ignorance;
  1203. ignorance = i;
  1204. }
  1205. Bterm(b);
  1206. }
  1207. int
  1208. ignore(char *p)
  1209. {
  1210. Ignorance *i;
  1211. readignore();
  1212. for(i = ignorance; i != nil; i = i->next)
  1213. if(cistrncmp(i->str, p, i->partial) == 0)
  1214. return 1;
  1215. return 0;
  1216. }
  1217. int
  1218. hdrlen(char *p, char *e)
  1219. {
  1220. char *ep;
  1221. ep = p;
  1222. do {
  1223. ep = strchr(ep, '\n');
  1224. if(ep == nil){
  1225. ep = e;
  1226. break;
  1227. }
  1228. ep++;
  1229. if(ep >= e){
  1230. ep = e;
  1231. break;
  1232. }
  1233. } while(*ep == ' ' || *ep == '\t');
  1234. return ep - p;
  1235. }
  1236. // rfc2047 non-ascii: =?charset?q?encoded-text?=
  1237. int
  1238. rfc2047convert(String *s, char *token, int len)
  1239. {
  1240. char charset[100], decoded[1024], *e, *x;
  1241. int l;
  1242. if(len == 0)
  1243. return -1;
  1244. e = token+len-2;
  1245. token += 2;
  1246. x = memchr(token, '?', e-token);
  1247. if(x == nil || (l=x-token) >= sizeof charset)
  1248. return -1;
  1249. memmove(charset, token, l);
  1250. charset[l] = 0;
  1251. token = x+1;
  1252. // bail if it doesn't fit
  1253. if(e-token > sizeof(decoded)-1)
  1254. return -1;
  1255. // bail if we don't understand the encoding
  1256. if(cistrncmp(token, "b?", 2) == 0){
  1257. token += 2;
  1258. len = dec64((uchar*)decoded, sizeof(decoded), token, e-token);
  1259. decoded[len] = 0;
  1260. } else if(cistrncmp(token, "q?", 2) == 0){
  1261. token += 2;
  1262. len = decquoted(decoded, token, e, 1);
  1263. if(len > 0 && decoded[len-1] == '\n')
  1264. len--;
  1265. decoded[len] = 0;
  1266. } else
  1267. return -1;
  1268. if(xtoutf(charset, &x, decoded, decoded+len) <= 0)
  1269. s_append(s, decoded);
  1270. else {
  1271. s_append(s, x);
  1272. free(x);
  1273. }
  1274. return 0;
  1275. }
  1276. char*
  1277. rfc2047start(char *start, char *end)
  1278. {
  1279. int quests;
  1280. if(*--end != '=')
  1281. return nil;
  1282. if(*--end != '?')
  1283. return nil;
  1284. quests = 0;
  1285. for(end--; end >= start; end--){
  1286. switch(*end){
  1287. case '=':
  1288. if(quests == 3 && *(end+1) == '?')
  1289. return end;
  1290. break;
  1291. case '?':
  1292. ++quests;
  1293. break;
  1294. case ' ':
  1295. case '\t':
  1296. case '\n':
  1297. case '\r':
  1298. /* can't have white space in a token */
  1299. return nil;
  1300. }
  1301. }
  1302. return nil;
  1303. }
  1304. // convert a header line
  1305. String*
  1306. stringconvert(String *s, char *uneaten, int len)
  1307. {
  1308. char *token, *p, *e;
  1309. s = s_reset(s);
  1310. p = uneaten;
  1311. for(e = p+len; p < e; ){
  1312. while(*p++ == '=' && (token = rfc2047start(uneaten, p))){
  1313. s_nappend(s, uneaten, token-uneaten);
  1314. if(rfc2047convert(s, token, p - token) < 0)
  1315. s_nappend(s, token, p - token);
  1316. uneaten = p;
  1317. for(; p<e && isspace(*p);)
  1318. p++;
  1319. if(p+2 < e && p[0] == '=' && p[1] == '?')
  1320. uneaten = p; // paste
  1321. }
  1322. }
  1323. if(p > uneaten)
  1324. s_nappend(s, uneaten, p-uneaten);
  1325. return s;
  1326. }
  1327. int
  1328. readheader(Message *m, char *buf, int off, int cnt)
  1329. {
  1330. char *p, *e;
  1331. int n, ns;
  1332. char *to = buf;
  1333. String *s;
  1334. p = m->header;
  1335. e = m->hend;
  1336. s = nil;
  1337. // copy in good headers
  1338. while(cnt > 0 && p < e){
  1339. n = hdrlen(p, e);
  1340. if(ignore(p)){
  1341. p += n;
  1342. continue;
  1343. }
  1344. // rfc2047 processing
  1345. s = stringconvert(s, p, n);
  1346. ns = s_len(s);
  1347. if(off > 0){
  1348. if(ns <= off){
  1349. off -= ns;
  1350. p += n;
  1351. continue;
  1352. }
  1353. ns -= off;
  1354. }
  1355. if(ns > cnt)
  1356. ns = cnt;
  1357. memmove(to, s_to_c(s)+off, ns);
  1358. to += ns;
  1359. p += n;
  1360. cnt -= ns;
  1361. off = 0;
  1362. }
  1363. s_free(s);
  1364. return to - buf;
  1365. }
  1366. int
  1367. headerlen(Message *m)
  1368. {
  1369. char buf[1024];
  1370. int i, n;
  1371. if(m->hlen >= 0)
  1372. return m->hlen;
  1373. for(n = 0; ; n += i){
  1374. i = readheader(m, buf, n, sizeof(buf));
  1375. if(i <= 0)
  1376. break;
  1377. }
  1378. m->hlen = n;
  1379. return n;
  1380. }
  1381. QLock hashlock;
  1382. uint
  1383. hash(ulong ppath, char *name)
  1384. {
  1385. uchar *p;
  1386. uint h;
  1387. h = 0;
  1388. for(p = (uchar*)name; *p; p++)
  1389. h = h*7 + *p;
  1390. h += ppath;
  1391. return h % Hsize;
  1392. }
  1393. Hash*
  1394. hlook(ulong ppath, char *name)
  1395. {
  1396. int h;
  1397. Hash *hp;
  1398. qlock(&hashlock);
  1399. h = hash(ppath, name);
  1400. for(hp = htab[h]; hp != nil; hp = hp->next)
  1401. if(ppath == hp->ppath && strcmp(name, hp->name) == 0){
  1402. qunlock(&hashlock);
  1403. return hp;
  1404. }
  1405. qunlock(&hashlock);
  1406. return nil;
  1407. }
  1408. void
  1409. henter(ulong ppath, char *name, Qid qid, Message *m, Mailbox *mb)
  1410. {
  1411. int h;
  1412. Hash *hp, **l;
  1413. qlock(&hashlock);
  1414. h = hash(ppath, name);
  1415. for(l = &htab[h]; *l != nil; l = &(*l)->next){
  1416. hp = *l;
  1417. if(ppath == hp->ppath && strcmp(name, hp->name) == 0){
  1418. hp->m = m;
  1419. hp->mb = mb;
  1420. hp->qid = qid;
  1421. qunlock(&hashlock);
  1422. return;
  1423. }
  1424. }
  1425. *l = hp = emalloc(sizeof(*hp));
  1426. hp->m = m;
  1427. hp->mb = mb;
  1428. hp->qid = qid;
  1429. hp->name = name;
  1430. hp->ppath = ppath;
  1431. qunlock(&hashlock);
  1432. }
  1433. void
  1434. hfree(ulong ppath, char *name)
  1435. {
  1436. int h;
  1437. Hash *hp, **l;
  1438. qlock(&hashlock);
  1439. h = hash(ppath, name);
  1440. for(l = &htab[h]; *l != nil; l = &(*l)->next){
  1441. hp = *l;
  1442. if(ppath == hp->ppath && strcmp(name, hp->name) == 0){
  1443. hp->mb = nil;
  1444. *l = hp->next;
  1445. free(hp);
  1446. break;
  1447. }
  1448. }
  1449. qunlock(&hashlock);
  1450. }
  1451. int
  1452. hashmboxrefs(Mailbox *mb)
  1453. {
  1454. int h;
  1455. Hash *hp;
  1456. int refs = 0;
  1457. qlock(&hashlock);
  1458. for(h = 0; h < Hsize; h++){
  1459. for(hp = htab[h]; hp != nil; hp = hp->next)
  1460. if(hp->mb == mb)
  1461. refs++;
  1462. }
  1463. qunlock(&hashlock);
  1464. return refs;
  1465. }
  1466. void
  1467. checkmboxrefs(void)
  1468. {
  1469. int f, refs;
  1470. Mailbox *mb;
  1471. qlock(&mbllock);
  1472. for(mb=mbl; mb; mb=mb->next){
  1473. qlock(mb);
  1474. refs = (f=fidmboxrefs(mb))+1;
  1475. if(refs != mb->refs){
  1476. fprint(2, "mbox %s %s ref mismatch actual %d (%d+1) expected %d\n", mb->name, mb->path, refs, f, mb->refs);
  1477. abort();
  1478. }
  1479. qunlock(mb);
  1480. }
  1481. qunlock(&mbllock);
  1482. }
  1483. void
  1484. post(char *name, char *envname, int srvfd)
  1485. {
  1486. int fd;
  1487. char buf[32];
  1488. fd = create(name, OWRITE, 0600);
  1489. if(fd < 0)
  1490. error("post failed");
  1491. sprint(buf, "%d",srvfd);
  1492. if(write(fd, buf, strlen(buf)) != strlen(buf))
  1493. error("srv write");
  1494. close(fd);
  1495. putenv(envname, name);
  1496. }