ref: 4ac4dc82da5199dd156f2c0c103f614c0e1d35c7
author: kvik <kvik@a-b.xyz>
date: Sun Jun 7 17:07:40 EDT 2020
Here begins history.
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,20 @@
+</$objtype/mkfile
+
+BIN=/bin
+TARG=rngfs
+OFILES=rngfs.$O
+
+all:V:
+
+test:V:
+ rngfs
+ <>[3]/mnt/random/integer {
+ echo range 5 10 >[1=3]
+ <[0=3] sed 999q | awk '$1 < 5 || $1 > 10 {exit $1}'
+ }
+ <>[3]/mnt/random/real {
+ echo range 5.351115 10.5215 >[1=3]
+ <[0=3] sed 999q | awk '$1 < 5.351115 || $1 > 10.5215 {exit $1}'
+ }
+
+</sys/src/cmd/mkone
--- /dev/null
+++ b/rngfs.c
@@ -1,0 +1,264 @@
+#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 *fs = 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(fs->min.i, fs->max.i));
+ break;
+ case Qreal:
+ n = snprint(buf, sizeof buf, "%f\n",
+ randomreal(fs->min.d, fs->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 *fs = 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:
+ fs->min.i = strtol(cb->f[1], nil, 10);
+ fs->max.i = strtol(cb->f[2], nil, 10);
+ break;
+ case Qreal:
+ fs->min.d = strtod(cb->f[1], nil);
+ fs->max.d = strtod(cb->f[1], nil);
+ }
+ break;
+ }
+ respond(r, nil);
+}
+
+Srv fileserver = {
+ .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(&fileserver, srvn, mtpt, MREPL);
+ exits(nil);
+}