#include #include #include #include #include #include void usage(void) { threadprint(2, "9pfilt [-abc] oldsrvfile newsrvname\n"); exits("usage"); } void postfd(char*, int); typedef struct Win Win; typedef struct Req Req; struct Win { char *name; QLock; int passing; int numgen; int id; int ctlfd; int addrfd; int bodyfd; int datafd; int tagfd; int eventfd; int msgfd; /* where messages come from */ Channel *rx; /* channel to receive messages */ Channel *tx; /* channel to send messages on */ Req *reqlist; /* actual messages */ Req **elist; }; struct Req { Fcall f; char buf[MAXFDATA+MAXMSG]; long n; int num; int passed; Req *link; }; /* read messages from fromfd and send them to rx channel */ void filterproc(void *a) { Win *w; Req *r; w = a; for(;;){ r = mallocz(sizeof *r, 1); assert(r != nil); r->n = sizeof r->buf; if(getS(w->msgfd, r->buf, &r->f, &r->n)) break; sendp(w->rx, r); } threadexitsall("read failed"); } void newwin(Win *w, char *name, int msgfd, Channel *rx, Channel *tx) { int fd; char buf[30], *p; w->name = name; w->msgfd = msgfd; fd = open("/dev/new/ctl", ORDWR); if(fd < 0) sysfatal("open /dev/new/ctl: %r"); if(read(fd, buf, 12) != 12) sysfatal("read id"); w->ctlfd = fd; w->id = atoi(buf); sprint(buf, "/dev/%d/", w->id); p = buf+strlen(buf); strcpy(p, "addr"); w->addrfd = open(buf, ORDWR); if(w->addrfd < 0) sysfatal("addr %s: %r", buf); strcpy(p, "body"); w->bodyfd = open(buf, OWRITE); if(w->bodyfd < 0) sysfatal("body %s: %r", buf); strcpy(p, "data"); w->datafd = open(buf, ORDWR); if(w->datafd < 0) sysfatal("body %s: %r", buf); strcpy(p, "tag"); w->tagfd = open(buf, ORDWR); if(w->tagfd < 0) sysfatal("tag %s: %r", buf); strcpy(p, "event"); w->eventfd = open(buf, OREAD); if(w->eventfd < 0) sysfatal("event %s: %r", buf); w->rx = rx; w->tx = tx; w->elist = &w->reqlist; } Req* copy(Req *r) { Req *n; n = mallocz(sizeof *n, 1); assert(n != nil); *n = *r; n->link = nil; return n; } void tag(Win *w, char *name) { threadprint(w->ctlfd, "cleartag\n"); threadprint(w->tagfd, "Look %s", name); } int gettext(Win *w, char *buf, long a, long b) { int n; threadprint(w->addrfd, "#%ld,#%ld", a, b); seek(w->datafd, 0, 0); if((n=read(w->datafd, buf, b-a)) != b-a) threadprint(2, "warning: read %ld ret %d\n", b-a, n); return n; } void settext(Win *w, char *buf, long a, long b) { threadprint(w->addrfd, "#%ld,#%ld", a, b); seek(w->datafd, 0, 0); write(w->datafd, buf, strlen(buf)); } void refreshwin(Win *w) { // threadprint(w->addrfd, ","); // threadprint(w->datafd, ""); } void acmewin(void *a) { Win *w; char buf[128]; int n; long num[4]; char *p; Req *r; w = a; threadprint(w->ctlfd, "name /9p/%s\n", w->name); tag(w, "Pass"); while((n=read(w->eventfd, buf, sizeof buf-1)) > 0){ Cont: buf[n] = 0; num[0] = strtol(buf+2, &p, 10); assert(p != nil); num[1] = strtol(p, &p, 10); assert(p != nil); num[2] = strtol(p, &p, 10); assert(p != nil); num[3] = strtol(p, &p, 10); assert(p != nil); p++; p[num[3]] = 0; if(num[2] & 2){ memmove(buf, p+num[3]+1, n = n - (p-buf) - num[3] - 1); goto Cont; } switch(buf[0]){ case 'E': /* write to body or tag file */ case 'F': /* other file write */ case 'K': /* keyboard */ case 'M':; /* mouse */ } switch(buf[1]){ case 'x': if(strcmp(p, "Pass")==0){ w->passing = 1; tag(w, "Nopass"); } if(strcmp(p, "Nopass")==0){ w->passing = 0; tag(w, "Pass"); } if(strcmp(p, "Get")==0){ refreshwin(w); } break; case 'X': if(num[1] - num[0] > 30) break; if(isdigit(p[0])){ n = atoi(p); for(r=w->reqlist; r; r=r->link) if(r->num == n) break; if(r == nil) break; if(r->passed) break; r->passed = 1; sendp(w->tx, copy(r)); num[0]--; num[1]++; gettext(w, buf, num[0], num[1]); threadprint(1, "get %ld %ld %.*s\n", num[1], num[0], (int)num[1]-num[0], buf); if(buf[0] == '[' && buf[num[1]-num[0]-1] == ']'){ buf[num[1]-num[0]-1] = 0; settext(w, buf+1, num[0], num[1]); } } break; } } } void reqproc(void *a) { Win *w; Req *r; w = a; while(r = recvp(w->rx)){ if(r->passed){ write(w->msgfd, r->buf, r->n); } else if(w->passing){ r->passed = 1; sendp(w->tx, copy(r)); } qlock(w); *w->elist = r; w->elist = &r->link; r->num = w->numgen++; threadprint(w->bodyfd, r->passed ? "%d/ %F\n" : "[%d]/ %F\n", r->num, &r->f); qunlock(w); } } Win srv, ker; void threadmain(int argc, char **argv) { int flag; int fd; int pfd[2]; Channel *k, *s; rfork(RFNOTEG); flag = 0; ARGBEGIN{ case 'a': flag |= MAFTER; break; case 'b': flag |= MBEFORE; break; case 'c': flag |= MCREATE; break; default: usage(); }ARGEND if(argc != 2) usage(); fmtinstall('F', fcallconv); fmtinstall('D', dirconv); if((fd = open(argv[0], ORDWR)) < 0) sysfatal("cannot open %s: %r", argv[0]); if(pipe(pfd)<0) sysfatal("pipe: %r"); postfd(argv[1], pfd[1]); k = chancreate(sizeof(Req*), 32); s = chancreate(sizeof(Req*), 32); newwin(&srv, "server", fd, k, s); newwin(&ker, "kernel", pfd[0], s, k); proccreate(filterproc, &ker, 8192); proccreate(filterproc, &srv, 8192); proccreate(acmewin, &ker, 8192); proccreate(acmewin, &srv, 8192); proccreate(reqproc, &ker, 8192); proccreate(reqproc, &srv, 8192); threadexits(0); } /* * read a message from fd and convert it. * ignore 0-length messages. */ char * getS(int fd, char *buf, Fcall *f, long *lp) { long m, n; int i; char *errstr; errstr = "EOF"; n = 0; for(i = 0; i < 3; i++){ n = read(fd, buf, *lp); if(n == 0){ continue; } if(n < 0) return "read error"; m = convM2S(buf, f, n); if(m == 0){ errstr = "bad type"; continue; } *lp = m; return 0; } *lp = n; return errstr; } void sysfatal(char *fmt, ...) { char buf[128]; va_list arg; va_start(arg, fmt); doprint(buf, buf+sizeof(buf), fmt, arg); va_end(arg); if(argv0) threadprint(2, "%s: %s\n", argv0, buf); else threadprint(2, "%s\n", buf); threadexitsall(buf); } void postfd(char *name, int pfd) { char buf[2*NAMELEN]; int fd; snprint(buf, sizeof buf, "/srv/%s", name); fd = create(buf, OWRITE, 0666); if(fd == -1) sysfatal("postsrv %s", buf); fprint(fd, "%d", pfd); close(fd); }