Plan 9 from Bell Labs’s /usr/web/sources/contrib/rsc/9pfilt.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#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);
}


Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.