7 #define err err9pserve /* Darwin x86 */
13 MAXMSG = 64, /* per connection */
14 MAXMSGSIZE = 4*1024*1024
17 typedef struct Hash Hash;
18 typedef struct Fid Fid;
19 typedef struct Msg Msg;
20 typedef struct Conn Conn;
21 typedef struct Queue Queue;
95 void *gethash(Hash**, uint);
96 int puthash(Hash**, uint, void*);
97 int delhash(Hash**, uint, void*);
98 Msg *mread9p(Ioproc*, int);
99 int mwrite9p(Ioproc*, int, uchar*);
100 uchar *read9ppkt(Ioproc*, int);
101 int write9ppkt(int, uchar*);
106 void msgincref(Msg*);
110 void *erealloc(void*, int);
112 int sendq(Queue*, void*);
114 void connthread(void*);
115 void connoutthread(void*);
116 void listenthread(void*);
117 void outputthread(void*);
118 void inputthread(void*);
119 void rewritehdr(Fcall*, uchar*);
120 void repack(Fcall*, uchar**);
121 int tlisten(char*, char*);
122 int taccept(int, char*);
123 int iolisten(Ioproc*, char*, char*);
124 int ioaccept(Ioproc*, int, char*);
125 int iorecvfd(Ioproc*, int);
126 int iosendfd(Ioproc*, int, int);
127 void mainproc(void*);
128 int ignorepipe(void*, char*);
130 void dorootstat(void);
135 fprint(2, "usage: 9pserve [-lnv] [-A aname afid] [-c addr] [-M msize] address\n");
136 fprint(2, "\treads/writes 9P messages on stdin/stdout\n");
137 threadexitsall("usage");
141 extern int _threaddebuglevel;
143 threadmain(int argc, char **argv)
145 char *file, *x, *addr;
149 x = getenv("verbose9pserve");
152 fprint(2, "verbose9pserve %s => %d\n", x, verbose);
159 xaname = EARGF(usage());
160 xafid = atoi(EARGF(usage()));
164 msize = atoi(EARGF(usage()));
167 addr = netmkaddr(EARGF(usage()), "net", "9fs");
168 if((fd = dial(addr, nil, nil, nil)) < 0)
169 sysfatal("dial %s: %r", addr);
189 if(attached && !versioned){
190 fprint(2, "-A must be used with -M\n");
198 fmtinstall('T', timefmt);
200 if((afd = announce(addr, adir)) < 0)
201 sysfatal("announce %s: %r", addr);
203 if(strncmp(addr, "unix!", 5) == 0)
205 file = smprint("%s.log", addr);
207 sysfatal("smprint log: %r");
208 if((fd = create(file, OWRITE, 0666)) < 0)
209 sysfatal("create %s: %r", file);
214 if(verbose) fprint(2, "%T 9pserve running\n");
215 proccreate(mainproc, nil, STACK);
225 atnotify(ignorepipe, 1);
226 fmtinstall('D', dirfmt);
227 fmtinstall('M', dirmodefmt);
228 fmtinstall('F', fcallfmt);
229 fmtinstall('H', encodefmt);
236 f.version = "9P2000";
239 n = convS2M(&f, vbuf, sizeof vbuf);
241 sysfatal("convS2M conversion error");
242 if(verbose > 1) fprint(2, "%T * <- %F\n", &f);
243 nn = write(1, vbuf, n);
245 sysfatal("error writing Tversion: %r\n");
246 n = read9pmsg(0, vbuf, sizeof vbuf);
248 sysfatal("read9pmsg failure");
249 if(convM2S(vbuf, n, &f) != n)
250 sysfatal("convM2S failure");
253 if(verbose > 1) fprint(2, "%T * -> %F\n", &f);
256 threadcreate(inputthread, nil, STACK);
257 threadcreate(outputthread, nil, STACK);
262 threadcreate(listenthread, nil, STACK);
267 ignorepipe(void *v, char *s)
270 if(strcmp(s, "sys: write on closed pipe") == 0)
272 if(strcmp(s, "sys: tstp") == 0)
274 if(strcmp(s, "sys: window size change") == 0)
276 fprint(2, "9pserve %s: %T note: %s\n", addr, s);
281 listenthread(void *arg)
288 threadsetname("listen %s", adir);
290 c = emalloc(sizeof(Conn));
291 c->fd = iolisten(io, adir, c->dir);
293 if(verbose) fprint(2, "%T listen: %r\n");
298 c->inc = chancreate(sizeof(void*), 0);
299 c->internal = chancreate(sizeof(void*), 0);
302 c->outqdead = chancreate(sizeof(void*), 0);
303 if(verbose) fprint(2, "%T incoming call on %s\n", c->dir);
304 threadcreate(connthread, c, STACK);
314 m->rpkt = emalloc(n);
315 nn = convS2M(&m->rx, m->rpkt, n);
317 sysfatal("convS2M conversion error");
319 sysfatal("sizeS2M and convS2M disagree");
320 sendq(m->c->outq, m);
329 m->tpkt = emalloc(n);
330 nn = convS2M(&m->tx, m->tpkt, n);
332 sysfatal("convS2M conversion error");
334 sysfatal("sizeS2M and convS2M disagree");
339 err(Msg *m, char *ename)
343 m->rx.tag = m->tx.tag;
352 t = emalloc(strlen(s)+1);
358 connthread(void *arg)
363 Msg *m, *om, *mm, sync;
368 threadsetname("conn %s", c->dir);
370 fd = ioaccept(io, c->fd, c->dir);
372 if(verbose) fprint(2, "%T accept %s: %r\n", c->dir);
377 threadcreate(connoutthread, c, STACK);
378 while((m = mread9p(io, c->fd)) != nil){
379 if(verbose > 1) fprint(2, "%T fd#%d -> %F\n", c->fd, &m->tx);
383 if(verbose > 1) fprint(2, "%T fd#%d: new msg %p\n", c->fd, m);
384 if(puthash(c->tag, m->tx.tag, m) < 0){
385 err(m, "duplicate tag");
391 m->rx.tag = m->tx.tag;
392 m->rx.msize = m->tx.msize;
393 if(m->rx.msize > msize)
395 m->rx.version = "9P2000";
396 m->rx.type = Rversion;
400 if((m->oldm = gethash(c->tag, m->tx.oldtag)) == nil){
401 m->rx.tag = m->tx.tag;
410 if(m->tx.afid != NOFID
411 && (m->afid = gethash(c->fid, m->tx.afid)) == nil){
412 err(m, "unknown fid");
417 m->fid = fidnew(m->tx.fid);
418 if(puthash(c->fid, m->tx.fid, m->fid) < 0){
419 err(m, "duplicate fid");
423 if(attached && m->afid==nil){
424 if(m->tx.aname[0] && strcmp(xaname, m->tx.aname) != 0){
425 err(m, "invalid attach name");
429 m->tx.aname = xaname;
430 m->tx.uname = getuser(); /* what srv.c used */
431 repack(&m->tx, &m->tpkt);
435 if((m->fid = gethash(c->fid, m->tx.fid)) == nil){
436 err(m, "unknown fid");
440 if(m->tx.newfid == m->tx.fid){
444 m->newfid = fidnew(m->tx.newfid);
445 if(puthash(c->fid, m->tx.newfid, m->newfid) < 0){
446 err(m, "duplicate fid");
454 err(m, "authentication not required");
458 err(m, "authentication rejected");
461 m->afid = fidnew(m->tx.afid);
462 if(puthash(c->fid, m->tx.afid, m->afid) < 0){
463 err(m, "duplicate fid");
469 if(m->tx.perm&(DMSYMLINK|DMDEVICE|DMNAMEDPIPE|DMSOCKET)){
470 err(m, "unsupported file type");
475 if(m->tx.mode&~(OTRUNC|3)){
476 err(m, "bad openfd mode");
491 if((m->fid = gethash(c->fid, m->tx.fid)) == nil){
492 err(m, "unknown fid");
499 /* have everything - translate and send */
504 m->tx.fid = m->fid->fid;
506 m->tx.newfid = m->newfid->fid;
508 m->tx.afid = m->afid->fid;
510 m->tx.oldtag = m->oldm->tag;
511 /* reference passes to outq */
513 while(c->nmsg >= MAXMSG){
519 if(verbose) fprint(2, "%T fd#%d eof; flushing conn\n", c->fd);
521 /* flush all outstanding messages */
522 for(i=0; i<NHASH; i++){
523 while((h = c->tag[i]) != nil){
525 msgincref(om); /* for us */
532 m->tx.oldtag = om->tag;
535 msgincref(m); /* for outq */
537 mm = recvp(c->internal);
539 msgput(m); /* got from recvp */
540 msgput(m); /* got from msgnew */
541 if(delhash(c->tag, om->ctag, om) == 0)
542 msgput(om); /* got from hash table */
543 msgput(om); /* got from msgincref */
548 * outputthread has written all its messages
549 * to the remote connection (because we've gotten all the replies!),
550 * but it might not have gotten a chance to msgput
551 * the very last one. sync up to make sure.
553 memset(&sync, 0, sizeof sync);
559 /* everything is quiet; can close the local output queue. */
563 /* should be no messages left anywhere. */
564 assert(c->nmsg == 0);
566 /* clunk all outstanding fids */
567 for(i=0; i<NHASH; i++){
568 for(h=c->fid[i]; h; h=hnext){
581 mm = recvp(c->internal);
584 msgput(m); /* got from recvp */
585 msgput(m); /* got from msgnew */
586 fidput(f); /* got from hash table */
594 assert(c->nmsg == 0);
595 assert(c->nfid == 0);
597 chanfree(c->internal);
607 openfdthread(void *v)
620 threadsetname("openfd %s", c->fdfid);
623 if(c->fdmode == OREAD){
625 if(verbose) fprint(2, "%T tread...");
630 m->tx.count = msize - IOHDRSZ;
631 m->tx.fid = fid->fid;
639 if(m->rx.type == Rerror){
640 /* fprint(2, "%T read error: %s\n", m->rx.ename); */
646 if(iowrite(io, c->fd, m->rx.data, m->rx.count) != m->rx.count){
647 /* fprint(2, "%T pipe write error: %r\n"); */
656 if(verbose) fprint(2, "%T twrite...");
660 if((n=ioread(io, c->fd, buf, n)) <= 0){
662 fprint(2, "%T pipe read error: %r\n");
669 m->tx.fid = fid->fid;
679 if(m->rx.type == Rerror){
680 /* fprint(2, "%T write error: %s\n", m->rx.ename); */
688 if(verbose) fprint(2, "%T eof on %d fid %d\n", c->fd, fid->fid);
695 if(verbose) fprint(2, "%T eof on %d fid %d ref %d\n", c->fd, fid->fid, fid->ref);
696 if(--fid->openfd == 0){
702 m->tx.fid = fid->fid;
713 chanfree(c->internal);
726 rerrstr(errs, sizeof errs);
728 /* XXX return here? */
730 if(verbose) fprint(2, "%T xopen pipe %d %d...", p[0], p[1]);
732 /* now we're committed. */
734 /* a new connection for this fid */
735 nc = emalloc(sizeof(Conn));
736 nc->internal = chancreate(sizeof(void*), 0);
742 nc->fdmode = m->tx.mode;
745 /* a thread to tend the pipe */
746 threadcreate(openfdthread, nc, STACK);
748 /* if mode is ORDWR, that openfdthread will write; start a reader */
749 if((m->tx.mode&3) == ORDWR){
750 nc = emalloc(sizeof(Conn));
751 nc->internal = chancreate(sizeof(void*), 0);
756 nc->fd = dup(p[0], -1);
757 threadcreate(openfdthread, nc, STACK);
760 /* steal fid from other connection */
761 if(delhash(m->c->fid, m->fid->cfid, m->fid) == 0)
764 /* rewrite as Ropenfd */
765 m->rx.type = Ropenfd;
767 m->rpkt = erealloc(m->rpkt, n+4);
768 PBIT32(m->rpkt+n, p[1]);
771 m->rpkt[4] = Ropenfd;
777 connoutthread(void *arg)
786 threadsetname("connout %s", c->dir);
787 while((m = recvq(c->outq)) != nil){
788 err = m->tx.type+1 != m->rx.type;
789 if(!err && m->isopenfd)
796 if(delhash(om->c->tag, om->ctag, om) == 0)
802 if(delhash(m->c->fid, m->fid->cfid, m->fid) == 0)
807 if(verbose) fprint(2, "%T auth error\n");
808 if(delhash(m->c->fid, m->afid->cfid, m->afid) == 0)
814 if(delhash(m->c->fid, m->fid->cfid, m->fid) == 0)
818 if(err || m->rx.nwqid < m->tx.nwname)
819 if(m->tx.fid != m->tx.newfid && m->newfid)
820 if(delhash(m->c->fid, m->newfid->cfid, m->newfid) == 0)
829 m->fid->isdir = (m->rx.qid.type & QTDIR);
832 if(delhash(m->c->tag, m->ctag, m) == 0)
834 if(verbose > 1) fprint(2, "%T fd#%d <- %F\n", c->fd, &m->rx);
835 rewritehdr(&m->rx, m->rpkt);
836 if(mwrite9p(io, c->fd, m->rpkt) < 0)
837 if(verbose) fprint(2, "%T write error: %r\n");
839 if(c->inputstalled && c->nmsg < MAXMSG)
845 sendp(c->outqdead, nil);
849 outputthread(void *arg)
856 threadsetname("output");
857 while((m = recvq(outq)) != nil){
859 sendp(m->c->outqdead, nil);
862 if(verbose > 1) fprint(2, "%T * <- %F\n", &m->tx);
863 rewritehdr(&m->tx, m->tpkt);
864 if(mwrite9p(io, 1, m->tpkt) < 0)
865 sysfatal("output error: %r");
869 fprint(2, "%T output eof\n");
874 inputthread(void *arg)
881 threadsetname("input");
882 if(verbose) fprint(2, "%T input thread\n");
885 while((pkt = read9ppkt(io, 0)) != nil){
888 fprint(2, "%T short 9P packet from server\n");
892 if(verbose > 2) fprint(2, "%T read %.*H\n", n, pkt);
894 if((m = msgget(tag)) == nil){
895 fprint(2, "%T unexpected 9P response tag %d\n", tag);
899 if((nn = convM2S(pkt, n, &m->rx)) != n){
900 fprint(2, "%T bad packet - convM2S %d but %d\n", nn, n);
905 if(verbose > 1) fprint(2, "%T * -> %F%s\n", &m->rx,
906 m->internal ? " (internal)" : "");
910 sendp(m->c->internal, m);
912 sendq(m->c->outq, m);
917 /*fprint(2, "%T input eof\n"); */
922 gethash(Hash **ht, uint n)
926 for(h=ht[n%NHASH]; h; h=h->next)
933 delhash(Hash **ht, uint n, void *v)
937 for(l=&ht[n%NHASH]; h=*l; l=&h->next)
940 if(verbose) fprint(2, "%T delhash %d got %p want %p\n", n, h->v, v);
951 puthash(Hash **ht, uint n, void *v)
957 h = emalloc(sizeof(Hash));
958 h->next = ht[n%NHASH];
975 fidtab = erealloc(fidtab, (nfidtab+1)*sizeof(fidtab[0]));
976 if(nfidtab == xafid){
977 fidtab[nfidtab++] = nil;
978 fidtab = erealloc(fidtab, (nfidtab+1)*sizeof(fidtab[0]));
980 fidtab[nfidtab] = emalloc(sizeof(Fid));
981 freefid = fidtab[nfidtab];
982 freefid->fid = nfidtab++;
1015 if(verbose > 1) fprint(2, "%T msgincref @0x%lux %p tag %d/%d ref %d=>%d\n",
1016 getcallerpc(&m), m, m->tag, m->ctag, m->ref, m->ref+1);
1026 msgtab = erealloc(msgtab, (nmsgtab+1)*sizeof(msgtab[0]));
1027 msgtab[nmsgtab] = emalloc(sizeof(Msg));
1028 freemsg = msgtab[nmsgtab];
1029 freemsg->tag = nmsgtab++;
1034 if(verbose > 1) fprint(2, "%T msgnew @0x%lux %p tag %d ref %d\n",
1035 getcallerpc(&x), m, m->tag, m->ref);
1041 * Clear data associated with connections, so that
1042 * if all msgs have been msgcleared, the connection
1043 * can be freed. Note that this does *not* free the tpkt
1044 * and rpkt; they are freed in msgput with the msg itself.
1045 * The io write thread might still be holding a ref to msg
1046 * even once the connection has finished with it.
1071 if(m->rx.type == Ropenfd && m->rx.unixfd >= 0){
1072 close(m->rx.unixfd);
1083 if(verbose > 1) fprint(2, "%T msgput 0x%lux %p tag %d/%d ref %d\n",
1084 getcallerpc(&m), m, m->tag, m->ctag, m->ref);
1109 if(n < 0 || n >= nmsgtab)
1114 if(verbose) fprint(2, "%T msgget %d = %p\n", n, m);
1128 sysfatal("out of memory allocating %d", n);
1134 erealloc(void *v, int n)
1139 sysfatal("out of memory reallocating %d", n);
1144 typedef struct Qel Qel;
1164 q = mallocz(sizeof(Queue), 1);
1172 sendq(Queue *q, void *p)
1176 e = emalloc(sizeof(Qel));
1197 while(q->head == nil)
1208 read9ppkt(Ioproc *io, int fd)
1213 n = ioreadn(io, fd, buf, 4);
1221 nn = ioreadn(io, fd, pkt+4, n-4);
1226 /* would do this if we ever got one of these, but we only generate them
1227 if(pkt[4] == Ropenfd){
1228 newfd = iorecvfd(io, fd);
1229 PBIT32(pkt+n-4, newfd);
1236 mread9p(Ioproc *io, int fd)
1242 if((pkt = read9ppkt(io, fd)) == nil)
1248 nn = convM2S(pkt, n, &m->tx);
1250 fprint(2, "%T read bad packet from %d\n", fd);
1259 mwrite9p(Ioproc *io, int fd, uchar *pkt)
1264 if(verbose > 2) fprint(2, "%T write %d %d %.*H\n", fd, n, n, pkt);
1265 if(verbose > 1) fprint(2, "%T before iowrite\n");
1266 if(iowrite(io, fd, pkt, n) != n){
1267 fprint(2, "%T write error: %r\n");
1270 if(verbose > 1) fprint(2, "%T after iowrite\n");
1271 if(pkt[4] == Ropenfd){
1272 nfd = GBIT32(pkt+n-4);
1273 if(iosendfd(io, fd, nfd) < 0){
1274 fprint(2, "%T send fd error: %r\n");
1282 restring(uchar *pkt, int pn, char *s)
1286 if(s < (char*)pkt || s >= (char*)pkt+pn)
1291 PBIT16((uchar*)s-1, n);
1295 repack(Fcall *f, uchar **ppkt)
1308 n = convS2M(f, pkt, nn);
1310 sysfatal("convS2M conversion error");
1312 sysfatal("convS2M and sizeS2M disagree");
1316 rewritehdr(Fcall *f, uchar *pkt)
1321 PBIT16(pkt+5, f->tag);
1325 restring(pkt, n, f->version);
1328 PBIT32(pkt+7, f->afid);
1329 restring(pkt, n, f->uname);
1330 restring(pkt, n, f->aname);
1333 PBIT16(pkt+7, f->oldtag);
1336 restring(pkt, n, f->uname);
1337 restring(pkt, n, f->aname);
1338 PBIT32(pkt+7, f->fid);
1339 PBIT32(pkt+11, f->afid);
1342 PBIT32(pkt+7, f->fid);
1343 PBIT32(pkt+11, f->newfid);
1344 for(i=0; i<f->nwname; i++)
1345 restring(pkt, n, f->wname[i]);
1348 restring(pkt, n, f->name);
1356 PBIT32(pkt+7, f->fid);
1359 PBIT32(pkt+7, f->fid);
1360 PBIT64(pkt+11, f->offset);
1363 restring(pkt, n, f->ename);
1369 _iolisten(va_list *arg)
1373 a = va_arg(*arg, char*);
1374 b = va_arg(*arg, char*);
1375 return listen(a, b);
1379 iolisten(Ioproc *io, char *a, char *b)
1381 return iocall(io, _iolisten, a, b);
1385 _ioaccept(va_list *arg)
1390 fd = va_arg(*arg, int);
1391 dir = va_arg(*arg, char*);
1392 return accept(fd, dir);
1396 ioaccept(Ioproc *io, int fd, char *dir)
1398 return iocall(io, _ioaccept, fd, dir);
1404 static char *mon[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1405 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
1409 tm = *localtime(time(0));
1410 return fmtprint(fmt, "%s %2d %02d:%02d:%02d.%03d",
1411 mon[tm.mon], tm.mday, tm.hour, tm.min, tm.sec,
1412 (int)(ns%1000000000)/1000000);