Plan 9 from Bell Labs’s /usr/web/sources/contrib/nemo/sys/src/cmd/mousefs.c

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


#include <u.h>
#include <libc.h>
#include <ctype.h>
#include <bio.h>
#include <thread.h>
#include <fcall.h>
#include <auth.h>
#include <draw.h>
#include <mouse.h>
#include <cursor.h>
#include <9p.h>
#include <b.h>

typedef struct Dev	Dev;

enum {
	Qdir = 0,
	Qmouse,
	Qctl,
	Qmax,

	Ndevs	= 64,
	Nevs	= 128,
	Stack	= 16 * 1024,

	Mevlen	= 1+12*4,	// see mouse(3).

	Stdxmax	= 1280,
	Stdymax	= 1024,


};

struct Dev {
	char	name;		// char to stampt events
	char	addr[50];	// IP for the machine servicing this
	int	con;		// to/from peer.
	int	cfd;		// ctl fd for con (for hanging up)
	Channel*evs;		// of char*; got from peer
	Channel*out;		// of char*; sent to peer
	int	sender;		// true if senderproc alive
	int	receiver;	// true if receiverproc alive
};

static int	newpeer(char* addr);

int mainstacksize = Stack;

static char	Ebad[] = "something bad happened";
static char	Eperm[] =	"permission denied";
static char	Enotexist[] =	"file not found";
static char	Eattach[] = 	"unknown specifier in attach";
static char	Ebadctl[] =	"bad control request";
static Lock	devslock;
static Dev	devs[2];
static int	debug;

static int	outm;	// output device
static int	inm;	// input device

static char*	kbdctl = "/dev/kbdctl";
static char*	localaddr;
static int	doauth = 1;
static char*	vname;
static char*	addr;
static Ref	readers;
static int	mousefd = -1;

#define dprint	if(debug)fprint
#define Dprint	if(debug>1)fprint

static int	xmin, xmax, ymin, ymax;

static Cursor whitearrow = {
	{0, 0},
	{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC, 
	 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF8, 0xFF, 0xFC, 
	 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC, 
	 0xF3, 0xF8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40, },
	{0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x06, 0xC0, 0x1C, 
	 0xC0, 0x30, 0xC0, 0x30, 0xC0, 0x38, 0xC0, 0x1C, 
	 0xC0, 0x0E, 0xC0, 0x07, 0xCE, 0x0E, 0xDF, 0x1C, 
	 0xD3, 0xB8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40, }
};


static void
changecursor(int w)
{
	static char curs[2*4+2*2*16];
	static int cfd = -1;
	static int dummy;
	static int last = -1;

	if (w == last)
		return;
	if (cfd < 0){
		Cursor* c = &whitearrow;
		cfd = open("/dev/cursor", OWRITE);
		BPLONG(curs+0*4, c->offset.x);
		BPLONG(curs+1*4, c->offset.y);
		memmove(curs+2*4, c->clr, 2*2*16);
	}
	if (cfd >=0){
		if (w)	// restore to default.
			write(cfd, curs, sizeof curs);
		else
			write(cfd, &dummy, sizeof(dummy));
	}
	last = w;
}

static int
alarmed(void *, char *s)
{
	if(strcmp(s, "alarm") == 0)
		return 1;
	return 0;
}

static void
getsizes(void)
{
	int	fd;
	char	buf[80];
	int	n;
	char*	p;
	char*	e;

	fd = open("/dev/wctl", OREAD);
	if (fd < 0){
		p = getenv("vgasize");
		if (p == nil)
			p = strdup("1024x768x8");
		strcpy(buf, p);
		free(p);
		p = strchr(buf, 'x');
		*p++ = 0;
		xmax = strtol(buf, 0, 0);
		e = strchr(p, 'x');
		*e = 0;
		ymax = strtol(p, 0, 0);
		xmin = ymin = 0;
	} else {
		n = read(fd, buf, sizeof(buf)-1);
		close(fd);
		buf[n] = 0;
		p = buf;
		xmin = strtol(p, &p, 0);
		ymin = strtol(p, &p, 0);
		xmax = strtol(p, &p, 0);
		ymax = strtol(p, &p, 0);
	}
	Dprint(2, "wsize: %d %d %d %d\n", xmin, ymin, xmax, ymax);
}

static int
isreclaim(char* ev)
{
	char	buf[60];
	int	x, y, b;
	char*	p;

	strecpy(buf, buf+sizeof(buf), ev);
	x = strtol(buf+2, &p, 0);
	y = strtol(p, &p, 0);
	b = strtol(p, &p, 0);
	return ( x - xmin < 10 && y - ymin < 10 && b == 1);
}

static int
htonmouse(char* ev)
{
	char	buf[60];
	int	x, y, b;
	ulong	m;
	double	xscale, yscale;
	char*	p;
	int	isnop;

	strecpy(buf, buf+sizeof(buf), ev);
	x = strtol(buf+2, &p, 0);
	y = strtol(p, &p, 0);
	b = strtol(p, &p, 0);
	m = strtoul(p, &p, 0);
	isnop = (x == 0 && y == 0 && b == 0);
	x -= xmin;
	y -= ymin;
	xscale = (double)Stdxmax / (double)(xmax - xmin);
	yscale = (double)Stdymax / (double)(ymax - ymin);
	x = (int)(xscale * (double)x);
	y = (int)(yscale * (double)y);
	seprint(buf+2, buf+sizeof(buf), "%10d %11d %11d %11lud ", x, y, b, m);
	strcpy(ev, buf);
	return !isnop;
}

static void
ntohmouse(char* ev)
{
	char	buf[60];
	int	x, y, b;
	ulong	m;
	double	xscale, yscale;
	char*	p;

	Dprint(2, "n m: %s\n", ev);
	strecpy(buf, buf+sizeof(buf), ev);
	x = strtol(buf+2, &p, 0);
	y = strtol(p, &p, 0);
	b = strtol(p, &p, 0);
	m = strtoul(p, &p, 0);
	xscale = (double)(xmax - xmin) / Stdxmax;
	yscale = (double)(ymax - ymin) / Stdymax;
	x = (int)(xscale * (double)x);
	y = (int)(yscale * (double)y);
	x += xmin;
	y += ymin;
	seprint(buf+2, buf+sizeof(buf), "%10d %11d %11d %11lud ", x, y, b, m);
	strcpy(ev, buf);
	Dprint(2, "h m: %s\n", ev);
}

static void
fstohmouse(char* ev)
{
	char	buf[60];
	int	x, y;
	char*	p;

	strecpy(buf, buf+sizeof(buf), ev);
	x = strtol(buf+1, &p, 0);
	y = strtol(p, &p, 0);
	seprint(buf, buf+sizeof(buf), "m%11d %11d %11d %11lud ", x, y, 0, 0UL);
	strcpy(ev, buf);
}

static char*
csquery(char *addr)
{
	static char buf[128];
	char* p;
	int fd, n;

	if (localaddr != nil)
	if (!addr || !strcmp(addr, "local"))
		return estrdup9p(localaddr);
	fd = open("/net/cs", ORDWR);
	if(fd < 0){
		fprint(2, "cannot open /net/cs: %r");
		return nil;
	}
	addr = netmkaddr(addr, "tcp", "11000");
	if(write(fd, addr, strlen(addr)) <= 0){
		fprint(2, "translating %s: %r\n", addr);
		close(fd);
		return nil;
	}
	seek(fd, 0, 0);
	buf[0] = 0;
	n = read(fd, buf, sizeof(buf)-1);
	close(fd);
	if (n < 0){
		fprint(2, "cannot read /net/cs: %r");
		return nil;
	}
	buf[n] = 0;
	p = strchr(buf, ' ');
	if (!p)
		return nil;
	p++;
	if (strchr(p, '!'))
		return smprint("tcp!%s", p);
	else {
		addr = smprint("tcp!%s!%s", sysname(), p);
		return csquery(addr);
	}
}

static int
islocal(char* a)
{
	char*	la;

	if (!a || !strcmp(a, "local"))
		return 1;
	if (!strcmp(a, sysname()) || !strcmp(a, localaddr))
		return 1;

	la = csquery(addr);
	if (la){
		if (!strcmp(a, la)){
			free(la);
			return 1;
		}
		free(la);
	}

	return 0;
}

static void
kbdsetdest(char* addr)
{
	static char*	last = nil;
	char*	c;
	int	fd, port;
	char	kaddr[50];

	fd = open(kbdctl, OWRITE);
	if (fd < 0){
		fprint(2, "mousefs: can't redirect kbd: %r\n");
		return;
	}
	if (last && !islocal(last)){
		dprint(2, "mousefs: kbd: close %s\n", last);
		fprint(fd, "close %s\n", last);
	}
	free(last);
	last = nil;
	strecpy(kaddr, kaddr+sizeof(kaddr), addr);
	c = strrchr(kaddr, '!');
	if (c){
		*c = 0;
		port = atoi(c+1) + 1;
		seprint(c, kaddr+sizeof(kaddr), "!%d", port);
	}
	dprint(2, "mousefs: kbd: call %s\n", kaddr);
	if (fprint(fd, "call %s\n", kaddr) < 0)
		dprint(2, "mousefs: kbd call failed: %r\n");
	last = strdup(kaddr);
	close(fd);
}

static void
local(void)
{
	dprint(2, "local\n");
	changecursor(0);
	inm = outm = 0;
	kbdsetdest("local");
}

static void
reclaim(void)
{
	if (inm == 1 || outm == 1)
		sendp(devs[1].out, "bye");
	local();
	while(devs[1].sender || devs[1].receiver){
		sleep(500);
		yield();
	}
}

static void
outgoing(void)
{
	dprint(2, "outgoing\n");
	changecursor(1);
	inm = 0;
	outm= 1;
	kbdsetdest(devs[1].addr);
}

static void
incoming(void)
{
	dprint(2, "incoming\n");
	changecursor(0);
	inm = 1;
	outm= 0;
	kbdsetdest("local");
}

static void
sendproc(void* a)
{
	Dev*	d = a;
	char*	e;

	threadsetname("sendproc");
	dprint(2, "sendproc %p starting\n", d);
	while(e = recvp(d->out)){
		if (strncmp(e, "bye", 3) == 0){
			dprint(2, "sendproc %p: bye\n", d);
			write(d->con, "bye", 3);
			continue;
		}
		if (strncmp(e, "call ", 5) == 0){
			write(d->con, e, strlen(e));
			free(e);
			continue;
		}
		if (strlen(e) != Mevlen){
			dprint(2, "sendproc %p: bad event: %s\n", d, e);
		} else if (e[0] == 'm'){
			e[1] = ' ';
			if (d != &devs[0])
				htonmouse(e);
			Dprint(2, "sent to %p %s\n", d, e);
			if (write(d->con, e, Mevlen) != Mevlen){
				fprint(2, "%s: write: %r\n", argv0);
				free(e);
				write(d->con, "bye", 3);
				break;
			}
		}
		free(e);
	}
	write(d->con, "bye", 3);
	write(d->cfd, "hangup", 6);
	close(d->cfd);
	d->cfd = -1;
	d->addr[0] = 0;
	d->sender = 0;
	dprint(2, "sendproc %p exiting\n", d);
	threadexits(nil);
}

static void
recvproc(void* a)
{
	char	buf[Mevlen+1];
	Dev*	d;
	int	n;
	char*	caddr;

	d = a;
	threadsetname("recvproc");
	dprint(2, "recvproc %p starting\n", d);
	caddr = nil;
	for(;;){
		n = read(d->con, buf, Mevlen);
		if (n == 0){
			dprint(2, "recvproc %p: eof\n", d);
			break;
		}
		if (n < 0){
			dprint(2, "%s: recvproc %p: %r\n", argv0, d);
			break;
		}
		buf[n] = 0;
		Dprint(2, "msread: %s\t%p i=%p o=%p\n", buf, d, &devs[inm], &devs[outm]);
		if (!strncmp(buf, "bye", 3)){
			dprint(2, "recvproc %p: bye\n", d);
			break;
		}
		if (!strncmp(buf, "call ", 5)){
			dprint(2, "recvproc %p: call\n", d);
			caddr = buf + 5;
			break;
		}
		if (d == &devs[0]){
			if (buf[0] == 'r'){
				getsizes();
			}
			if (isreclaim(buf)){
				dprint(2, "mousefs: reclaim\n");
				reclaim();
				continue;
			}
			Dprint(2, "mouse %p send: %s\n", d, buf);
			buf[1] = d->name;
			if (outm == 0){
				if (readers.ref > 0)
					sendp(devs[outm].evs, estrdup9p(buf));
			} else
				if (buf[0] == 'm')
					sendp(devs[outm].out, estrdup9p(buf));
		} else {
			ntohmouse(buf);
			Dprint(2, "mouse %p deliver: %s\n", d, buf);
			buf[1] = d->name;
			sendp(devs[0].out, estrdup9p(buf));
			if (readers.ref > 0)
				sendp(devs[0].evs, estrdup9p(buf));
		}
	}
	sendp(d->out, nil);
	write(d->con, "bye", 3);
	write(d->cfd, "hangup", 6);
	close(d->cfd);
	close(d->con);
	d->con = -1;
	dprint(2, "recvproc %p exiting\n", d);
	local();
	d->receiver = 0;
	if (caddr != nil && 0){	// not safe. Still too easy to make loops
		reclaim();
		if (newpeer(caddr))
			outgoing();
	}
	threadexits(nil);
}

static void
initdev(Dev* dev, char name, char* addr)
{
	dev->evs = chancreate(sizeof(char*), Nevs);
	dev->out = chancreate(sizeof(char*), Nevs);
	dev->name = name;
	dev->con = -1;
	dev->cfd = -1;
	if (addr)
		strecpy(dev->addr, dev->addr+sizeof(dev->addr), addr);
}

static Dev*
newdev(char* addr, int fd)
{
	Dev*	dev;

	if (islocal(addr)){	// allowed just once
		dev = &devs[0];
		if (dev->con >= 0)
			return nil;
	} else
		dev = &devs[1];
	strecpy(dev->addr, dev->addr+sizeof(dev->addr), addr);
	dev->con = fd;
	dev->cfd = -1;
	dev->receiver = dev->sender = 1;
	procrfork(recvproc, dev, Stack, RFNAMEG|RFNOTEG);
	procrfork(sendproc, dev, Stack, RFNAMEG|RFNOTEG);
	dprint(2, "mousefs: newdev %s\n", addr);
	return dev;
}


static void
fsattach(Req *r)
{
	char *spec;

	spec = r->ifcall.aname;
	if(spec != nil && spec[0] != 0){
		respond(r, Eattach);
		return;
	}

	r->ofcall.qid = (Qid){Qdir, 0, QTDIR};
	r->fid->qid = r->ofcall.qid;
	respond(r, nil);
}

static void
fsopen(Req *r)
{
	int	p;

	r->ifcall.mode &= 3;
	if (r->fid->qid.type == QTAUTH || r->ifcall.mode == OREAD){
		r->fid->omode = r->ifcall.mode;
	} else {
		p = r->fid->qid.path;
		switch(p){
		case Qdir:
			respond(r, Eperm);
			return;
		case Qmouse:
			incref(&readers);
		case Qctl:
			r->fid->omode = r->ifcall.mode;
			break;
		default:
			respond(r, Ebad);
			return;
		}
	}
	respond(r, nil);
}

static int
dirgen(int i, Dir *d, void*)
{
	if(i > 1)
		return -1;
	memset(d, 0, sizeof *d);
	d->uid = estrdup9p("sys");
	d->gid = estrdup9p("sys");
	d->length = 0;
	switch(i){
	case -1:
		d->qid.type = QTDIR;
		d->qid.path = Qdir;
		d->mode = 0555|DMDIR;
		d->name = estrdup9p("/");
		break;
	case 0:
		d->mode = 0660;
		d->qid.path = Qmouse;
		d->name = estrdup9p("mouse");
		break;
	case 1:
		d->mode = 0220;
		d->qid.path = Qctl;
		d->name = estrdup9p("mousectl");
		break;
	default:
		return -1;
	}
	return 0;
}

void
mreadproc(void* a)
{
	static char	locked = 0;
	char*	ev;
	int	b;
	Req*	r;
	Channel* mreadreq = a;

	threadsetname("mreadproc");
	for(;;){
		r = recvp(mreadreq);

		/* Merging mouse streams may cause pressed buttons to
		 * be `released' because of events that come from other
		 * mouses. To prevent this, a mouse that is holding a
		 * button down is locking the mouse (other ones ignored).
		 * A gone device releases the lock as well.
		 */
		for(;;){
			ev = recvp(devs[0].evs);
			if (ev == nil){
				fprint(2, "%s: nil event?", argv0);
				continue;
			}
			if (strlen(ev) != Mevlen){
				fprint(2,"%s: bad mouse event: [%s]\n", argv0, ev);
				continue;
			}
			if (!locked || ev[1] == locked)
				break;
			free(ev);
		}
		b = (ev[1+11+1+11+1+10] != '0');
		if (locked && locked == ev[1] && !b){
			locked = 0;
		} else if (!locked && b){
			locked = ev[1];
		}
		ev[1] = ' ';
		r->ofcall.count = strlen(ev);
		if (r->ifcall.count < r->ofcall.count)
			r->ofcall.count = r->ifcall.count;
		memmove(r->ofcall.data, ev, r->ofcall.count);

		Dprint(2, "fsread: %s\n", ev);
		free(ev);
		respond(r, nil);
	}
}

static void
fsread(Req *r)
{
	static Channel* mreadreqc = nil;
	static char	locked = 0;
	char	m[200];
	char*	e;
	int	p;
	int	i;

	p = r->fid->qid.path;
	switch(p){
	case Qdir:
		dirread9p(r, dirgen, nil);
		break;
	case Qmouse:
		/* We can't service the read ourselves. If we block
		 * then any request on the fs would have to wait.
		 * This is a BAD thing because we bind MBEFORE at /dev.
		 */
		if (mreadreqc == nil){
			mreadreqc = chancreate(sizeof(Req*), Nevs);
			proccreate(mreadproc, mreadreqc, Stack);
		}
		sendp(mreadreqc, r);
		return;
	case Qctl:
		e = m;
		lock(&devslock);
		for (i = 0; i < nelem(devs); i++)
			if (devs[i].addr[0])
				e = seprint(e, m+sizeof(m), "%s\n", devs[i].addr);
		unlock(&devslock);
		readstr(r, m);
		break;
	default:
		respond(r, Ebad);
		return;
	}
	respond(r, nil);
}

static int
authfd(int fd, char* role)
{
	AuthInfo*i;

	i = nil;
	alarm(5*1000);
	USED(i);
	i = auth_proxy(fd, nil, "proto=p9any user=%s role=%s", getuser(), role);
	alarm(0);
	if (i == nil)
		return 0;
	auth_freeAI(i);
	return 1;
}

static int
newpeer(char* addr)
{
	int	fd;
	int	cfd;
	Dev*	d;
	char*	na;

	na = netmkaddr(addr, "tcp", "mouse");
	if (islocal(addr) || islocal(na)){
		dprint(2, "%s: newpeer: local addr: %s\n", argv0, addr);
		return 0;
	}
	fd = dial(na, 0, 0, &cfd);
	if (fd < 0){
		fprint(2, "mousefs: dial %s: %r\n", addr);
		return 0;
	}
	if (doauth && !authfd(fd, "client")){
		fprint(2, "mousefs: can't auth to %s: %r\n", addr);
		close(fd);
		close(cfd);
		return 0;
	}
	if (d = newdev(addr, fd)){
		d->cfd = cfd;
		fprint(d->cfd, "keepalive 2000");
	}
	return d != nil;
}

static char*
ctl(char* msg)
{
	char*	args[4];
	int	nargs;
	char*	addr;
	char	call[Mevlen];
	char*	na;

	/* call address
	 * close address
	 */
	nargs = tokenize(msg, args, nelem(args));
	if (nargs != 2)
		return Ebadctl;
	if (strcmp(args[0], "call") == 0){
		addr = csquery(args[1]);
		if (addr == nil){
			reclaim();
			return Enotexist;
		}
		if (inm == 0){
			reclaim();
			if (!newpeer(addr)){
				free(addr);
				return Enotexist;
			}
			outgoing();
		} else {
			na = netmkaddr(addr, "tcp", "11000");
			if (!islocal(addr) && !islocal(na)){
				seprint(call,call+sizeof(call),"call %s",args[1]);
				nbsendp(devs[inm].out, estrdup9p(call));
				reclaim();
			}
		}
		free(addr);
	} else if (strcmp(args[0], "close") == 0){
		reclaim();
	} else if (strcmp(args[0], "debug") == 0){
		debug = atoi(args[1]);
	} else {
		return Ebadctl;
	}
	return nil;
}

static void
fswrite(Req *r)
{
	static int mctl = -1;
	int	p;
	char	msg[80];
	int	n;
	char*	e;
	p = r->fid->qid.path;
	if (mctl < 0)
		mctl = open("#m/mousectl", OWRITE|OCEXEC);
	switch(p){
	case Qmouse:
		n = r->ifcall.count;
		if (n > sizeof(msg)-1)
			n = sizeof(msg)-1;
		memmove(msg, r->ifcall.data, n);
		msg[n] = 0;
		r->ofcall.count = n;
		Dprint(2, "fswrite: %s\n", msg);
		fstohmouse(msg);
		sendp(devs[0].out, estrdup9p(msg));
		if (inm != 0)
			sendp(devs[inm].out, estrdup9p(msg));
		break;
	case Qdir:
		respond(r, Ebad);
		return;
	case Qctl:
		n = r->ofcall.count = r->ifcall.count;
		if (n > sizeof(msg)-1)
			n = sizeof(msg)-1;
		memmove(msg, r->ifcall.data, n);
		msg[n] = 0;
		e = ctl(msg);
		if (e != nil){
			if (strcmp(e, Ebadctl) == 0){
				if(write(mctl, r->ifcall.data, n) < 0){
					respond(r, Ebadctl);
					return;
				}
			} else {
				respond(r, e);
				return;
			}
		}
		break;
	default:
		respond(r, Ebad);
		return;
	}
	respond(r, nil);
}

static char*
fswalk1(Fid *fid, char *name, Qid* q)
{

	if (fid->qid.path != Qdir){
		if(strcmp(name, "..") == 0){
			fid->qid.path = Qdir;
			fid->qid.type = QTDIR;
			*q = fid->qid;
			return nil;
		}
		return Enotexist;
	}
	if (strcmp(name, "..") == 0){
		fid->qid.path = Qdir;
		fid->qid.type = QTDIR;
	} else if (strcmp(name, "mouse") == 0){
		fid->qid.path = Qmouse;
		fid->qid.type = 0;
	} else if (strcmp(name, "mousectl") == 0){
		fid->qid.path = Qctl;
		fid->qid.type = 0;
	} else
		return Enotexist;
	*q = fid->qid;
	return nil;
}

static void
fsstat(Req *r)
{
	int q;

	q = r->fid->qid.path;
	switch(q){
	case Qdir:
		dirgen(-1, &r->d, nil);
		break;
	case Qmouse:
		dirgen(0, &r->d, nil);
		break;
	case Qctl:
		dirgen(1, &r->d, nil);
		break;
	}
	respond(r, nil);
}

static void
fsclunk(Fid* f)
{
	if (f->omode >= 0 && f->qid.path == Qmouse)
		decref(&readers);
}

static Srv mfs=
{
.attach=fsattach,
.open=	fsopen,
.read=	fsread,
.stat=	fsstat,
.write= fswrite,
.walk1= fswalk1,
.destroyfid= fsclunk,
};

static void
listener(void *a)
{
	int	afd, lfd;
	char	adir[40];
	char	ldir[40];
	char*	addr = a;
	int	dfd;
	NetConnInfo*i;
	Dev*	dev;

	threadsetname("listener");
	threadnotify(alarmed, 1);
	afd = announce(addr, adir);
	if (afd < 0)
		sysfatal("can't announce: %r");
	for(;;){
		lfd = listen(adir, ldir);
		if (lfd < 0)
			sysfatal("can't listen: %r");
		reclaim();
		dfd = accept(lfd, ldir);
		i = getnetconninfo(ldir, dfd);
		if (doauth && !authfd(dfd, "server")){
			fprint(2, "auth failed for %s\n", i->rsys);
			close(lfd);
			close(dfd);
		} else if (dev = newdev(i->rsys, dfd)){
			dev->receiver = dev->sender = 1;
			dev->cfd = lfd;
			fprint(dev->cfd, "keepalive 2000");
			proccreate(recvproc, dev, Stack);
			proccreate(sendproc, dev, Stack);
			dprint(2, "mousefs: call from %s\n", dev->addr);
			incoming();
		} else {
			close(lfd);
			fprint(2, "local call ignored\n");
		}
		freenetconninfo(i);
	}
}


void
setpri(int pri)
{
	int	pid;
	char*	s;
	int	fd;

	pid = getpid();
	s = smprint("/proc/%d/ctl", pid);
	fd = open(s, OWRITE);
	free(s);
	s = smprint("pri %d", pri);
	write(fd, s, strlen(s));
	free(s);
	close(fd);
}

void
srvproc(void* a)
{
	int*	p = a;

	threadsetname("srvproc");
	getsizes();
	mousefd = open("/dev/mouse", ORDWR|OCEXEC);
	if (mousefd < 0)
		sysfatal("can't open mouse: %r");
	initdev(&devs[0], 'a', localaddr);
	initdev(&devs[1], 'b', nil);
	//setpri(13);
	newdev(localaddr, mousefd);
	proccreate(listener, estrdup9p(addr), Stack);
	threadnotify(alarmed, 1);
	close(p[1]);
	mfs.infd = p[0];
	mfs.outfd= p[0];
	mfs.nopipe= 1;
	mfs.srvfd = -1;
	srv(&mfs);
	dprint(2, "mousefs: srvproc exiting\n");
	threadexitsall(nil);
}

static void
announceproc(void*)
{
	int	afd = -1;
	char*	cnstr;

	cnstr = strchr(vname, ' ');
	if (cnstr)
		*cnstr++ = 0;

	for(;;){
		afd = announcevol(afd, addr, vname, cnstr);
		sleep(10 * 1000);
	}
}


void
usage(void)
{
	fprint(2, "usage: %s [-AdD] [-m mnt] [-n addr]\n", argv0);
	exits("usage");
}

void
threadmain(int argc, char **argv)
{
	char*	mnt;
	int	p[2];

	mnt = "/dev";
	addr= "tcp!*!11000";
	ARGBEGIN{
	case 'A':
		doauth = 0;
		break;
	case 'D':
		chatty9p++;
	case 'd':
		debug++;
		break;
	case 'a':
	case 'n':
		addr = EARGF(usage());
		break;
	case 'm':
		mnt = EARGF(usage());
		break;
	case 'V':
		vname = EARGF(usage());
		break;
	default:
		usage();
	}ARGEND;

	if(argc!= 0)
		usage();
	chdir("/");
	addr = netmkaddr(addr, "tcp", "11000");
	localaddr = csquery(addr);

	if(pipe(p) < 0)
		sysfatal("pipe: %r");
	procrfork(srvproc, p, Stack, RFNAMEG|RFFDG|RFNOTEG);
	close(p[0]);
	if (mount(p[1], -1, mnt, MBEFORE, "") < 0)
		sysfatal("mount: %r");
	if (addr != nil && vname != nil)
		proccreate(announceproc, 0, 8*1024);
	threadexits(nil);
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].