shithub: cursedfs

ref: 2e592b5e00e8f2489eba725135e3aab33438a9c0
dir: cursedfs/main.c

View raw version
#include <u.h>
#include <libc.h>
#include <auth.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>
#include "fs.h"

struct File9 {
	Ref;
	int		id;		// index in array; qid.path
	char	*name;	// of file
};

// All active files in the fs
File9 *files[Nfiles];

// Commands log ;; 4 entries, 1024 wide
char clog[Ncmd][Cmdwidth];
int mainstacksize = 65536;

// Prototypes for 9p handler functions
static void		fsattach(Req *r);
static int		getdirent(int n, Dir *d, void *);
static void		fsread(Req *r);
static void		fswrite(Req *r);
static char*	fswalk1(Fid * fid, char *name, Qid *qid);
static char*	fsclone(Fid *fid, Fid *newfid);
static void		fsstat(Req *r);

char	*mnt, *srvd;

// Srv structure to handle incoming 9p communications
static Srv srvfs = 
{
	.attach		=	fsattach,
	.read		=	fsread,
	.write		=	fswrite,
	.walk1		=	fswalk1,
	.clone		= 	fsclone,
	.stat		=	fsstat,
};


// Usage output
void
usage(void)
{
	fprint(2, "usage: %s [-D] [-s srv] [-m mnt]\n", argv0);
	threadexitsall("usage");
}

// Push a message into the log
char*
handlecmd(char* str)
{
	putstring(runesmprint(" %s", str), 6);

	int maxtoks = 10;
	char *cmd;
	char **toks = calloc(maxtoks, sizeof (char*));
	int ntoks;
	ntoks = tokenize(str, toks, maxtoks);
	if(ntoks < 1)
		return "fail: supply at least one command";

	cmd = toks[0];
	if(strcmp(cmd, "clear") == 0){
		clear();
		
	}else if(strcmp(cmd, "newwin") == 0){
		// We can keep a ring of buffers for the screen and flip thru
		return "fail: not impl";
		
	}else if(strcmp(cmd, "delwin") == 0){
		return "fail: not impl";
		
	}else if(strcmp(cmd, "endwin") == 0){
		return "fail: not impl";
		
	}else if(strcmp(cmd, "mvprintw") == 0){
		return "fail: not impl";
		
	}else if(strcmp(cmd, "mvaddch") == 0){
		// Expect: mvaddch x y r
		if(ntoks < 4)
			return "usage: mvaddch x y r";

		
		
		
	}else if(strcmp(cmd, "getch") == 0){
		return "fail: not impl";
		
	}else if(strcmp(cmd, "initscr") == 0){
		// We start the screen anyways, so leave it be
		;
		
	}else if(strcmp(cmd, "raw") == 0){
		return "fail: not impl";
		
	}else if(strcmp(cmd, "noecho") == 0){
		return "fail: not impl";
		
	}else if(strcmp(cmd, "cursset") == 0){
		return "fail: not impl";
		
	}else if(strcmp(cmd, "setescdelay") == 0){
		return "fail: not impl";
		
	}else if(strcmp(cmd, "refresh") == 0){
		return "fail: not impl";
		
	}else if(strcmp(cmd, "wrefresh") == 0){
		return "fail: not impl";
		
	}else if(strcmp(cmd, "keypad") == 0){
		return "fail: not impl";
	}
	free(toks);
	return nil;
}

// Print the log
char*
screen2str(void)
{
	char str[Ncmd * Cmdwidth];
	memset(str, '\0', Ncmd * Cmdwidth);

	int i;
	for(i = Ncmd-1; i >= 0; i--)
		strncat(str, clog[i], strlen(clog[i]));

	return str;
}

// FS starter
void
initfs(void*)
{
	
	// Setup ctl file
	File9 ctl = (File9) { (Ref){ 0 }, 0, "ctl" };
	files[0] = &ctl;
	
	// Setup log file
	File9 log = (File9) { (Ref){ 0 }, 1, "screen" };
	files[1] = &log;


	threadpostmountsrv(&srvfs, srvd, mnt, MREPL|MCREATE);
	threadexits(nil);
}


// Drain channels
void
drainer(void*)
{
	int mv, kbv;
	Alt alts[3];
	alts[0].c = mchan;
	alts[0].v = &mv;
	alts[0].op = CHANRCV;
	alts[1].c = kbchan;
	alts[1].v = &kbv;
	alts[1].op = CHANRCV;
	alts[2].op = CHANEND;

	for(;;)
	switch(alt(alts)){
	case 0:
		putstring(runesmprint(" %d", mv), 2);
		break;
	case 1:
		putstring(runesmprint(" %d", kbv), 4);
		break;
	default:
		break;
	}

}


/* A simple 9p fileserver to show a minimal set of operations */
void
threadmain(int argc, char *argv[])
{

	srvd = nil;
	mnt = "/mnt/simplefs";

	ARGBEGIN{
	case 'D':
		chatty9p++;
		break;
	case 's':
		srvd = EARGF(usage());
		break;
	case 'm':
		mnt = EARGF(usage());
		break;
	default:
		usage();
	}ARGEND;

	if(argc != 0)
		usage();

	kbchan = chancreate(sizeof (int), 20);
	mchan = chancreate(sizeof (int), 20);

	proccreate(drainer, nil, mainstacksize);
	proccreate(initfs, nil, mainstacksize);
	proccreate(initscreen, nil, mainstacksize);
	threadexits(nil);
}

// Handle 9p attach -- independent implementation
static void
fsattach(Req *r)
{
	r->fid->qid = (Qid) { 0, 0, QTDIR };
	r->ofcall.qid = r->fid->qid;
	respond(r, nil);
}

// Get directory entries for stat and such -- independent implementation
static int
getdirent(int n, Dir *d, void *)
{
	d->atime = time(nil);
	d->mtime = d->atime;
	d->uid = estrdup9p(getuser());
	d->gid = estrdup9p(d->uid);
	d->muid = estrdup9p(d->uid);
	if(n == -1){
		d->qid = (Qid) {0, 0, QTDIR};
		d->mode = 0775;
		d->name = estrdup9p("/");
		d->length = 0;
	}else if(n >= 0 && n < Nfiles && files[n] != nil){
		d->qid = (Qid) {n, 0, 0};
		d->mode = 0664;
		d->name = estrdup9p(files[n]->name);
	}else
		return -1;
	return 0;
}

// Handle 9p read
static void
fsread(Req *r)
{
	Fid		*fid;
	Qid		q;
	char	readmsg[Ncmd * Cmdwidth];
	readmsg[0] = '\0';

	fid = r->fid;
	q = fid->qid;
	if(q.type & QTDIR){
		dirread9p(r, getdirent, nil);
		respond(r, nil);
		return;
	}

	switch(q.path){
	case 0:
		// ctl file
		strcpy(readmsg, "ctl file is unreadable.\n");
		break;
	case 1:
		// log file
		// TODO -- attach stdout to write to the read stream
		// strcpy(readmsg, "log shows prior commands.\n");
		strcpy(readmsg, screen2str());
		break;
	default:
		strcpy(readmsg, "Nothing special in this read.\n");
	}
	
	// Set the read reply string
	readstr(r, readmsg);
	
	// Respond to the 9p request
	respond(r, nil);
}

// Handle 9p write
static void
fswrite(Req *r)
{
	Fid		*fid;
	Qid		q;
	char	str[Cmdwidth];

	fid = r->fid;
	q = fid->qid;
	if(q.type & QTDIR){
		respond(r, "permission denied.");
		return;
	}
	if(r->ifcall.count > sizeof(str) - 1){
		respond(r, "string too large");
		return;
	}
	memmove(str, r->ifcall.data, r->ifcall.count);
	str[r->ifcall.count] = 0;
	
	// At this point, str contains the written bytes
	
	char *msg;
	switch(q.path){
	case 0:
		// ctl file
		msg = handlecmd(str);
		if(msg != nil)
			respond(r, msg);
		break;
	default:
		respond(r, "only ctl may be written to");
		return;
	}
	
	respond(r, nil);
}

// Handle 9p walk -- independent implementation
static char *
fswalk1(Fid * fid, char *name, Qid *qid)
{
	Qid q;
	int i;

	q = fid->qid;
	if(!(q.type && QTDIR)){
		if(!strcmp(name, "..")){
			fid->qid = (Qid) {0, 0, QTDIR};
			*qid = fid->qid;
			fid->aux = nil;
			return nil;
		}
	}else{
		for(i = 0; i < Nfiles; i++)
			if(files[i] && !strcmp(name, files[i]->name)){
				fid->qid = (Qid){i, 0, 0};
				incref(files[i]);
				fid->aux = files[i];
				*qid = fid->qid;
				return nil;
			}
	}
	return "no such directory.";
}

// Handle 9p stat -- independent implementation
static void
fsstat(Req *r)
{
	Fid *fid;
	Qid q;

	fid = r->fid;
	q = fid->qid;
	if(q.type & QTDIR)
		getdirent(-1, &r->d, nil);
	else
		getdirent(q.path, &r->d, nil);
	respond(r, nil);
}

// Handle 9p clone -- independent implementation
static char *
fsclone(Fid *fid, Fid *newfid)
{
	File9 *f;
	
	f = fid->aux;
	if(f != nil)
		incref(f);
	newfid->aux = f;
	return nil;
}