Plan 9 from Bell Labs’s /usr/web/sources/contrib/axel/substfs/direct/substfs.c

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


#include <u.h>
#include <libc.h>
#include <bio.h>
#include <auth.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>

ulong	messagesize = IOHDRSZ+8192;
char	statbuf[IOHDRSZ+8192];
int subfd;
int editfd = -1;
int tidefd = -1;

int	old9p = -1;
uchar*	rxbuf;
uchar*	txbuf;
char	Ewstatbuffer[] = "bogus wstat buffer";

void
usage(void)
{
	fprint(2, "usage: substfs [...] /srv/service | -c command | -n networkaddress [remote2local local2remote]\n");
	exits("usage");
}

void*
emalloc(ulong n)
{
	void *p;

	p = malloc(n);
	if(p == 0)
		sysfatal("malloc(%ld) fails", (long)n);
	memset(p, 0, n);
	return p;
}

void
getfcallnew(int fd, Fcall *fc, int have)
{
	int len;

	if(have > BIT32SZ)
		sysfatal("cannot happen: %r");

	if(have < BIT32SZ && readn(fd, rxbuf+have, BIT32SZ-have) != BIT32SZ-have)
		sysfatal("couldn't read message: %r");

	len = GBIT32(rxbuf);
	if(len <= BIT32SZ)
		sysfatal("bogus message");

	len -= BIT32SZ;
	if(readn(fd, rxbuf+BIT32SZ, len) != len)
		sysfatal("short message: %r");

	if(convM2S(rxbuf, len+BIT32SZ, fc) != len+BIT32SZ)
		sysfatal("badly sized message type %d: %r", rxbuf[0]);
}

void
putfcallnew(int wfd, Fcall *tx)
{
	ulong n;

	if((n = convS2M(tx, txbuf, messagesize)) == 0)
		sysfatal("couldn't format message type %d: %r", tx->type);
	fprint(2, "substfs: %F\n", tx);
	if(write(wfd, txbuf, n) != n)
		sysfatal("couldn't send message: %r");
}

void
getfcall(int fd, Fcall *fc)
{
	//getfcallnew(fd, fc, 0);

	int res;
	res = read9pmsg(fd, rxbuf, messagesize);
	if (res < 0) {
		// fprint(2, "%us", rxbuf);
		sysfatal("couldn't read message: %r");
	}
	if (res == 0)
		sysfatal("end of file on fd");

	if(convM2S(rxbuf, messagesize, fc) == 0)
		sysfatal("badly sized message type %d: %r", rxbuf[0]);
	fprint(2, "substfs: %F\n", fc);

}

static
long
dirpackage(uchar *buf, long ts, Dir **d)
{
	char *s;
	long ss, i, n, nn, m;

	*d = nil;
	if(ts <= 0)
		return 0;

	/*
	 * first find number of all stats, check they look like stats, & size all associated strings
	 */
	ss = 0;
	n = 0;
	for(i = 0; i < ts; i += m){
		m = BIT16SZ + GBIT16(&buf[i]);
		if(statcheck(&buf[i], m) < 0)
			break;
		ss += m;
		n++;
	}

	if(i != ts)
		return -1;

	*d = malloc(n * sizeof(Dir) + ss);
	if(*d == nil)
		return -1;

	/*
	 * then convert all buffers
	 */
	s = (char*)*d + n * sizeof(Dir);
	nn = 0;
	for(i = 0; i < ts; i += m){
		m = BIT16SZ + GBIT16((uchar*)&buf[i]);
		if(nn >= n || convM2D(&buf[i], m, *d + nn, s) != m){
			free(*d);
			*d = nil;
			return -1;
		}
		nn++;
		s += m;
	}

	return nn;
}

void
mydirread9p(Fcall *rx, Fcall *tx, Dir* d, long ndir)
{
	int start;
	uchar *p, *ep;
	uint rv;

	if(rx->offset == 0)
		start = 0;
	else
		// start = r->fid->dirindex;
		start = 0;

	p = (uchar*)tx->data;
	ep = p+rx->count;

	while((p < ep) && (start < ndir)){
		rv = convD2M(&d[start], p, ep-p);
		if(rv <= BIT16SZ)
			break;
		p += rv;
		start++;
	}
	// r->fid->dirindex = start;
	tx->count = p - (uchar*)tx->data;
}

static
char*
do_edit(int fd, char *src, char *fn)
{
	char buf[1024];
	if (fd >= 0) {
		fprint(2, "substfs: %swrite... %s\n", fn, src);
		write(fd, src, strlen(src)+1);
		fprint(2, "substfs: %swrite... done\n", fn);
		fprint(2, "substfs: %sread... \n", fn);
		read(fd, buf, sizeof(buf));
		fprint(2, "substfs: %sread... %s\n", fn, buf);
		if (strcmp(src, buf) != 0) {
			return strdup(buf);
		} 
	}
	return src;
}

static
char*
do_tide(int fd, char *src, char *fn)
{
	char buf[1024];
	char *p;
	if (fd >= 0) {
		fprint(2, "substfs: %swrite... %s\n", fn, src);
		fprint(fd, "%s\n", src);
		fprint(2, "substfs: %swrite... done\n", fn);
		fprint(2, "substfs: %sread... \n", fn);
		read(fd, buf, sizeof(buf));
		if (p = strchr(buf, '\n'))
			*p = '\0';
		fprint(2, "substfs: %sread... %s\n", fn, buf);
		if (strcmp(src, buf) != 0) {
			return strdup(buf);
		} 
	}
	return src;
}

static
char*
edit(char *src)
{
	return do_edit(editfd, src, "edit");
}


static
char*
tide(char *src)
{
	return do_tide(tidefd, src, "tide");
}

static
void
handle(Fcall *rx, Fcall *tx)
{
	fprint(2, "substfs: putfcallnew...\n");
	putfcallnew(subfd, rx);
	fprint(2, "substfs: putfcallnew... done\n");
	fprint(2, "substfs: getfcall... \n");
	getfcall(subfd, tx);
	fprint(2, "substfs: getfcall... done\n");
}

void
seterror(Fcall *f, char *error)
{
	f->type = Rerror;
	f->ename = error ? error : "programmer error";
}

void
rversion(Fcall *rx, Fcall *tx, Fidpool *fp)
{
	USED(fp);
	handle(rx, tx);
}

void
rauth(Fcall *rx, Fcall *tx, Fidpool *fp)
{
	Fid *f = allocfid(fp, rx->afid);
	handle(rx, tx);
	fprint(2, "substfs: fid: %ld\n", f->fid);
	f->qid = tx->qid;
	closefid(f);
}

void
rattach(Fcall *rx, Fcall *tx, Fidpool *fp)
{
	Fid *f = allocfid(fp, rx->fid);
	handle(rx, tx);
	fprint(2, "substfs: fid: %ld\n", f->fid);
	f->qid = tx->qid;
	closefid(f);
}

void
rwalk(Fcall *rx, Fcall *tx, Fidpool *fp)
{
	Fid *f;
	long i;
	for (i = 0; i < rx->nwname; i++) {
		rx->wname[i] = tide(rx->wname[i]);
	}
	handle(rx, tx);
	if ((rx->nwname == tx->nwqid)) {
		f= allocfid(fp, rx->newfid);
		fprint(2, "substfs: fid: %ld\n", f->fid);
		f->qid = tx->wqid[tx->nwqid-1];
		closefid(f);
	} else {
		fprint(2, "substfs: walk failed\n");
	}
}

void
ropen(Fcall *rx, Fcall *tx, Fidpool *fp)
{
	Fid *f= lookupfid(fp, rx->fid);
	handle(rx, tx);
	fprint(2, "substfs: fid: %ld\n", f->fid);
	f->qid = tx->qid;
	closefid(f);
}

void
rcreate(Fcall *rx, Fcall *tx, Fidpool *fp)
{
	Fid *f;
	handle(rx, tx);
	if (tx->type != Rerror) {
		f= allocfid(fp, rx->fid);
		fprint(2, "substfs: fid: %ld\n", f->fid);
		f->qid = tx->qid;
		closefid(f);
	} else {
		fprint(2, "substfs: create failed\n");
	}
}

void
rread(Fcall *rx, Fcall *tx, Fidpool *fp)
{
	Dir *d;
	long nd;
	long i;
	Fid *f= lookupfid(fp, rx->fid);
	handle(rx, tx);
	fprint(2, "substfs: fid: %ld\n", f->fid);
	fprint(2, "substfs: qid.type: %x\n", f->qid.type);
	if (f->qid.type&QTDIR) {
		fprint(2, "substfs: directory!\n");
		nd = dirpackage((uchar*)tx->data, tx->count, &d);
		for (i=0; i < nd; i++) {
			fprint(2, "substfs-rread[%ld]: %D\n", i, &d[i]);
			d[i].name = edit(d[i].name);
		}
		mydirread9p(rx, tx, d, nd);
	} else {
		fprint(2, "substfs: NO directory!\n");
	}
	closefid(f);
}

void
rwrite(Fcall *rx, Fcall *tx, Fidpool *fp)
{
	Fid *f= lookupfid(fp, rx->fid);
	handle(rx, tx);
	fprint(2, "substfs: fid: %ld\n", f->fid);
	closefid(f);
}

void
rclunk(Fcall *rx, Fcall *tx, Fidpool *fp)
{
	Fid *f= lookupfid(fp, rx->fid);
	handle(rx, tx);
	fprint(2, "substfs: fid: %ld\n", f->fid);
	removefid(fp, rx->fid);
}

void
rremove(Fcall *rx, Fcall *tx, Fidpool *fp)
{
	Fid *f= lookupfid(fp, rx->fid);
	handle(rx, tx);
	fprint(2, "substfs: fid: %ld\n", f->fid);
	closefid(f);
}

void
rstat(Fcall *rx, Fcall *tx, Fidpool *fp)
{
	Fid *f= lookupfid(fp, rx->fid);
	Dir d;
	handle(rx, tx);
	fprint(2, "substfs: fid: %ld\n", f->fid);
	if (convM2D(tx->stat, tx->nstat, &d, statbuf) <= BIT16SZ){
		seterror(tx, Ewstatbuffer);
		fprint(2, "substfs-rstat: Ewstatbuffer\n");
	} else {
		fprint(2, "substfs-rstat: %D\n", &d);
	}
	closefid(f);
}

void
rwstat(Fcall *rx, Fcall *tx, Fidpool *fp)
{
	Fid *f= lookupfid(fp, rx->fid);
	handle(rx, tx);
	fprint(2, "substfs: fid: %ld\n", f->fid);
	closefid(f);
}

void
fidnop(Fid*)
{
}

void
serve(int rfd, int wfd)
{
	Fcall rx, tx;
	Fidpool* fp;

	fp = allocfidpool(fidnop);

	for(;;){
		getfcall(rfd, &rx);

		if(chatty9p)
			fprint(2, "<- %F\n", &rx);

		memset(&tx, 0, sizeof tx);
		tx.type = rx.type+1;
		tx.tag = rx.tag;
		switch(rx.type){
		case Tflush:
			break;
		case Tversion:
			rversion(&rx, &tx, fp);
			break;
		case Tauth:
			rauth(&rx, &tx, fp);
			break;
		case Tattach:
			rattach(&rx, &tx, fp);
			break;
		case Twalk:
			rwalk(&rx, &tx, fp);
			break;
		case Tstat:
			// tx.stat = databuf;
			rstat(&rx, &tx, fp);
			break;
		case Twstat:
			rwstat(&rx, &tx, fp);
			break;
		case Topen:
			ropen(&rx, &tx, fp);
			break;
		case Tcreate:
			rcreate(&rx, &tx, fp);
			break;
		case Tread:
			// tx.data = databuf;
			rread(&rx, &tx, fp);
			break;
		case Twrite:
			rwrite(&rx, &tx, fp);
			break;
		case Tclunk:
			rclunk(&rx, &tx, fp);
			break;
		case Tremove:
			rremove(&rx, &tx, fp);
			break;
		default:
			fprint(2, "unknown message %F\n", &rx);
			seterror(&tx, "bad message");
			break;
		}

		if(chatty9p)
			fprint(2, "-> %F\n", &tx);

		putfcallnew(wfd, &tx);
	}
}

int
connectcmd(char *cmd)
{
	int p[2];

	if(pipe(p) < 0)
		return -1;
	switch(fork()){
	case -1:
		fprint(2, "fork failed: %r\n");
		_exits("exec");
	case 0:
		dup(p[0], 0);
		dup(p[0], 1);
		close(p[1]);
		execl("/bin/rc", "rc", "-c", cmd, nil);
		fprint(2, "exec failed: %r\n");
		_exits("exec");
	default:
		close(p[0]);
		return p[1];
	}
}

void
main(int argc, char **argv)
{
	char *mtpt, *service;
	int cmd, net;
	int sfd[2];

	mtpt = nil;
	service = nil;
	cmd = 0;
	net = 0;
	ARGBEGIN{
	case 'D':
		chatty9p++;
		break;
	case 's':
		service = EARGF(usage());
		break;
	case 'm':
		mtpt = EARGF(usage());
		break;
	case 'c':
		cmd = 1;
		break;
	case 'n':
		net = 1;
		break;
	default:
		usage();
	}ARGEND

	if(argc < 1)
		usage();

	fmtinstall('D', dirfmt);
	fmtinstall('M', dirmodefmt);
	fmtinstall('F', fcallfmt);

	rxbuf = emalloc(messagesize);
	txbuf = emalloc(messagesize);

	if(cmd && net)
		usage();

	if(cmd)
		subfd = connectcmd(argv[0]);
	else if(net){
		subfd = dial(netmkaddr(argv[0], "net", "9fs"), 0, 0, 0);
		if(subfd < 0)
			sysfatal("dial: %r");
	}else{
		subfd = open(argv[0], ORDWR);
		if(subfd < 0)
			sysfatal("open: %r");
	}

	//postmountsrv(&substsrv, service, mtpt, MREPL);
	//exits(nil);

	if (argc == 3) {
		editfd = connectcmd(argv[1]);
		tidefd = connectcmd(argv[2]);
	}

	if(pipe(sfd) < 0)
		sysfatal("pipe: %r");
	if(service)
		if(postfd(service, sfd[0]) < 0)
			sysfatal("postfd %s: %r", service);
	serve(sfd[1], sfd[1]);
	
}


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.