ref: 2e592b5e00e8f2489eba725135e3aab33438a9c0
dir: /main.c/
#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;
}