ref: 0d8ff1fb65431a90927ebbeeab130a492ade82f4
dir: /rngfs.c/
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>
void
usage(void)
{
fprint(2, "%s [-D] [-m mtpt] [-s srv]\n", argv0);
exits("usage");
}
enum {
Qroot,
Qinteger,
Qreal,
};
typedef struct F {
char *name;
Qid qid;
ulong mode;
} F;
typedef struct Fstate {
/* range [min, max) */
union {long i; double d;} min;
union {long i; double d;} max;
} Fstate;
F root = {
"/", {Qroot, 0, QTDIR}, 0555|DMDIR
};
F roottab[] = {
"integer", {Qinteger, 0, QTFILE}, 0444,
"real", {Qreal, 0, QTFILE}, 0444,
};
enum {Cmdrange};
Cmdtab cmd[] = {
Cmdrange, "range", 3,
};
F*
filebypath(uvlong path)
{
int i;
if(path == Qroot)
return &root;
for(i = 0; i < nelem(roottab); i++)
if(path == roottab[i].qid.path)
return &roottab[i];
return nil;
}
void
xattach(Req *r)
{
r->fid->qid = filebypath(Qroot)->qid;
r->ofcall.qid = r->fid->qid;
respond(r, nil);
}
char*
xwalk1(Fid *fid, char *name, Qid *qid)
{
int i;
switch(fid->qid.path){
case Qroot:
for(i = 0; i < nelem(roottab); i++){
if(strcmp(roottab[i].name, name) == 0){
*qid = roottab[i].qid;
fid->qid = *qid;
return nil;
}
}
if(strcmp("..", name) == 0){
*qid = root.qid;
fid->qid = *qid;
return nil;
}
break;
}
return "not found";
}
void
xopen(Req *r)
{
uvlong path = r->fid->qid.path;
Fstate *st;
st = emalloc9p(sizeof(Fstate));
r->fid->aux = st;
switch(path){
case Qinteger:
st->min.i = 0L;
st->max.i = 0x7fffffffL;
break;
case Qreal:
st->min.d = 0.0;
st->max.d = 1.0;
break;
}
respond(r, nil);
}
void
xdestroyfid(Fid *fid)
{
if(fid->aux != nil)
free(fid->aux);
}
void
fillstat(Dir *d, uvlong path, char *user)
{
F *f;
f = filebypath(path);
d->name = estrdup9p(f->name);
d->qid = f->qid;
d->mode = f->mode;
d->uid = estrdup9p(user);
d->gid = estrdup9p(user);
d->muid = estrdup9p(user);
d->length = 0;
d->atime = time(0);
d->mtime = time(0);
}
void
xstat(Req *r)
{
fillstat(&r->d, r->fid->qid.path, r->fid->uid);
respond(r, nil);
return;
}
int
rootgen(int n, Dir *d, void *aux)
{
Req *r = aux;
if(n >= nelem(roottab))
return -1;
fillstat(d, roottab[n].qid.path, r->fid->uid);
return 0;
}
long
randominteger(long min, long max)
{
if(min > max){int t = min; min = max; max = t;}
return min+((max-min)/(double)0x7fffffff*lrand());
}
double
randomreal(double min, double max)
{
if(min > max){double t = min; min = max; max = t;}
return min+(max-min)*frand();
}
void
xread(Req *r)
{
char buf[128];
int n = 0;
uvlong path = r->fid->qid.path;
Fstate *st = r->fid->aux;
if(path == Qroot){
dirread9p(r, rootgen, r);
respond(r, nil);
return;
}
switch(path){
case Qinteger:
n = snprint(buf, sizeof buf, "%ld\n",
randominteger(st->min.i, st->max.i));
break;
case Qreal:
n = snprint(buf, sizeof buf, "%f\n",
randomreal(st->min.d, st->max.d));
break;
}
if(r->ifcall.count < n)
n = r->ifcall.count;
r->ofcall.count = n;
memmove(r->ofcall.data, buf, n);
respond(r, nil);
}
void
xwrite(Req *r)
{
uvlong path = r->fid->qid.path;
Cmdbuf *cb;
Cmdtab *cp;
Fstate *st = r->fid->aux;
cb = parsecmd(r->ifcall.data, r->ifcall.count);
cp = lookupcmd(cb, cmd, nelem(cmd));
if(cp == nil){
respondcmderror(r, cb, "%r");
return;
}
switch(cp->index){
case Cmdrange:
switch(path){
case Qinteger:
st->min.i = strtol(cb->f[1], nil, 10);
st->max.i = strtol(cb->f[2], nil, 10);
break;
case Qreal:
st->min.d = strtod(cb->f[1], nil);
st->max.d = strtod(cb->f[2], nil);
}
break;
}
respond(r, nil);
}
Srv fs = {
.attach = xattach,
.walk1 = xwalk1,
.open = xopen,
.stat = xstat,
.read = xread,
.write = xwrite,
.destroyfid = xdestroyfid,
};
void
main(int argc, char *argv[])
{
char *mtpt, *srvn;
mtpt = "/mnt/random";
srvn = nil;
ARGBEGIN{
case 'm':
mtpt = EARGF(usage());
break;
case 's':
srvn = EARGF(usage());
break;
case 'D':
chatty9p++;
break;
default:
usage();
}ARGEND;
srand(time(0));
postmountsrv(&fs, srvn, mtpt, MREPL);
exits(nil);
}