#include <u.h>
#include <libc.h>
#include <auth.h>
#include <fcall.h>
#include <thread.h>
#include <ctype.h>
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);
}
|