shithub: ridefs

Download patch

ref: 38f2878c44f584d472560c9a426d01cdd3fb99cb
parent: 8eef000ed6e16e02354e6798f227223cc38b2d42
author: B. Wilson <x@wilsonb.com>
date: Wed Jun 18 02:07:10 EDT 2025

Add sanity check tests

--- a/ridefs.c
+++ b/ridefs.c
@@ -19,30 +19,15 @@
 
 	/* internal use */
 	char *user;
-	char *pres;  /* previous result */
+	char *pres;     /* previous result */
+	char *rinfo;
+	char *qctl;
 	long time0;
 	int id;
-	int oio;     /* io opened */
-	int iopid;   /* read/write fork */
-	int fd;      /* data */
-	int cfd;     /* ctl */
-
-	/* id reply info */
-	int Rapiversion;
-	int Rport;
-	int Rpid;
-	char *Ripaddress;
-	char *Rvendor;
-	char *Rlanguage;
-	char *Rversion;
-	char *Rmachine;
-	char *Rarch;
-	char *Rproject;
-	char *Rprocess;
-	char *Ruser;
-	char *Rtoken;
-	char *Rdate;
-	char *Rplatform;
+	int oio;        /* io opened */
+	int iopid;      /* read/write fork */
+	int fd;         /* data */
+	int cfd;        /* ctl */
 };
 
 enum {
@@ -52,6 +37,7 @@
 		Qclient,
 			Qctl,
 			Qio,
+			Qrinfo,
 	QCOUNT
 };
 
@@ -62,6 +48,7 @@
 		nil,
 			"ctl",
 			"io",
+			"rinfo",
 };
 
 struct Rfid {
@@ -70,12 +57,13 @@
 	int client;
 };
 
-#define RIDESRV_VERS 0
+#define VERSION 0
 static Client *cpool;
 static char *mtpt;
 static char *service;
 static char *net;
 static char *user;
+static char *qrctl;
 static ulong umask;
 static long bufsz;
 static long time0;
@@ -103,12 +91,52 @@
 
 char*
 estrdup(char *s){
+	if(s == nil)
+		return nil;
+
 	s = estrdup9p(s);
 	setrealloctag(s, getcallerpc(&s));
 	return s;
 }
 
+Client*
+clientref(int i){
+	if(i < 0 || i > nclients)
+		return nil;
+	return &cpool[i];
+}
+
 int
+genqrctl(void){
+	sprintf(qrctl,
+		"version %i\n"
+		"bufsz %u\n"
+		"nclients %u\n"
+		"debug %i\n"
+		"timeout %i\n"
+		"umask 0%hlo\n",
+		VERSION, bufsz, nclients,
+		debug, timeout, umask);
+
+	return strlen(qrctl);
+}
+
+int
+genqctl(int client){
+	Client *c;
+
+	c = clientref(client);
+	sprintf(c->qctl,
+		"%i\n"
+		"connect %s\n"
+		"timeout %i\n"
+		"umask 0%hlo\n",
+		client, c->addr, c->timeout, c->umask);
+
+	return strlen(c->qctl);
+}
+
+int
 mkclient(void){
 	Client *c;
 	int i;
@@ -116,7 +144,7 @@
 	for(i = 0; i < nclients; i++)
 		if(cpool[i].ref == 0)
 			break;
-	if(i == nelem(cpool))
+	if(i == nclients)
 		return -1;
 	c = &cpool[i];
 
@@ -126,18 +154,12 @@
 	c->umask = umask;
 	c->user = estrdup(getuser());
 	c->time0 = time(0);
+	c->qctl = ecalloc(bufsz);
+	genqctl(i);
 
 	return i;
 }
 
-Client*
-clientref(int i){
-	if(i < 0 || i > nclients)
-		return nil;
-
-	return &cpool[i];
-}
-
 void
 rmclient(int i){
 	Client *c;
@@ -146,20 +168,10 @@
 	if(c == nil || decref(c))
 		return;
 
-	if(c->Ripaddress) free(c->Ripaddress);
-	if(c->Rvendor) free(c->Rvendor);
-	if(c->Rlanguage) free(c->Rlanguage);
-	if(c->Rversion) free(c->Rversion);
-	if(c->Rmachine) free(c->Rmachine);
-	if(c->Rarch) free(c->Rarch);
-	if(c->Rproject) free(c->Rproject);
-	if(c->Rprocess) free(c->Rprocess);
-	if(c->Ruser) free(c->Ruser);
-	if(c->Rtoken) free(c->Rtoken);
-	if(c->Rdate) free(c->Rdate);
-	if(c->Rplatform) free(c->Rplatform);
-
 	if(c->user) free(c->user);
+	if(c->pres) free(c->pres);
+	if(c->qctl) free(c->qctl);
+	if(c->rinfo) free(c->rinfo);
 	if(c->fd) close(c->fd);
 	if(c->cfd) close(c->cfd);
 
@@ -167,9 +179,9 @@
 }
 
 static void
-mkqid(Qid *q, int k, Client *c){
-	q->vers = RIDESRV_VERS;
-	q->path = ((u64int)c->id<<32) | k&0xffffffff;
+mkqid(Qid *q, int k, int client){
+	q->vers = VERSION;
+	q->path = ((u64int)client<<32) | k&0xffffffff;
 
 	switch(k){
 	case Qroot:
@@ -225,7 +237,7 @@
 char *
 rideinit(int client){
 	int fd;
-	char *addr, *pld, *s;
+	char *addr, *buf, *s, *e;
 	Client *c;
 	JSON *j;
 	JSONEl *d;
@@ -237,26 +249,26 @@
 	c = clientref(client);
 	c->fd = fd;
 
-	pld = ecalloc(bufsz);
-	if(0 > readmsg(fd, pld, bufsz))
+	buf = ecalloc(bufsz);
+	if(0 > readmsg(fd, buf, bufsz))
 		return "failed to read handshake";
-	if(0 != strcmp(pld, "SupportedProtocols=2"))
+	if(0 != strcmp(buf, "SupportedProtocols=2"))
 		return "unrecognized protocol";
-	free(pld);
+	free(buf);
 
-	pld = "UsingProtocol=2";
-	if(0 > writemsg(fd, pld, strlen(pld)))
+	buf = "UsingProtocol=2";
+	if(0 > writemsg(fd, buf, strlen(buf)))
 		return "failed to write handshake";
 		
-	pld = "[\"Identify\",{\"apiVersion\":1,\"identity\":1}]";
-	if(0 > writemsg(fd, pld, strlen(pld)))
+	buf = "[\"Identify\",{\"apiVersion\":1,\"identity\":1}]";
+	if(0 > writemsg(fd, buf, strlen(buf)))
 		return "failed to send identification message";
 
-	pld = ecalloc(bufsz);
-	if(0 > readmsg(fd, pld, bufsz))
+	buf = ecalloc(bufsz);
+	if(0 > readmsg(fd, buf, bufsz))
 		return "failed to receive identification message";
-	j = jsonparse(pld);
-	free(pld);
+	j = jsonparse(buf);
+	free(buf);
 	if(j == nil || j->t != JSONArray || nil == j->first)
 		return "unrecognized reply";
 	if(nil == (s = jsonstr(j->first->val)) || 0 != strcmp(s, "ReplyIdentify"))
@@ -264,51 +276,31 @@
 	if(nil == (d = j->first->next) || d->val->t != JSONObject)
 		return "malformed identification reply";
 
-	c->Rapiversion = jsonbyname(d->val, "apiVersion")->n;
-	c->Rport       = jsonbyname(d->val, "Port")->n;
-	c->Rpid        = jsonbyname(d->val, "pid")->n;
-	c->Ripaddress  = estrdup(jsonstr(jsonbyname(d->val, "IPAddress")));
-	c->Rvendor     = estrdup(jsonstr(jsonbyname(d->val, "Vendor")));
-	c->Rlanguage   = estrdup(jsonstr(jsonbyname(d->val, "Language")));
-	c->Rversion    = estrdup(jsonstr(jsonbyname(d->val, "version")));
-	c->Rmachine    = estrdup(jsonstr(jsonbyname(d->val, "Machine")));
-	c->Rarch       = estrdup(jsonstr(jsonbyname(d->val, "arch")));
-	c->Rproject    = estrdup(jsonstr(jsonbyname(d->val, "Project")));
-	c->Rprocess    = estrdup(jsonstr(jsonbyname(d->val, "Process")));
-	c->Ruser       = estrdup(jsonstr(jsonbyname(d->val, "User")));
-	c->Rtoken      = estrdup(jsonstr(jsonbyname(d->val, "token")));
-	c->Rdate       = estrdup(jsonstr(jsonbyname(d->val, "date")));
-	c->Rplatform   = estrdup(jsonstr(jsonbyname(d->val, "platform")));
+	c->rinfo = s = ecalloc(bufsz);
+	buf = ecalloc(bufsz);
+	e = s + bufsz-1;
+	for(; d != nil; d = d->next){
+		switch(d->val->t){
+		case JSONBool:
+		case JSONNumber:
+			sprintf(buf, "%s %i\n", d->name, d->val->n); break;
+		case JSONString:
+			sprintf(buf, "%s %s\n", d->name, d->val->s); break;
+		}
+		s = strecpy(s, e, buf);
+	}
+	free(buf);
 
 	jsonfree(j);
 	return nil;
 }
 
-
 long
-readqrctl(char **buf){
-	char *b;
-
-	b = ecalloc(bufsz);
-	sprintf(b,
-		"version %i\n"
-		"bufsz %u\n"
-		"nclients %u\n"
-		"debug %i\n"
-		"timeout %i\n"
-		"umask %o\n",
-		RIDESRV_VERS, bufsz, nclients,
-		debug, timeout, umask);
-
-	*buf = b;
-	return strlen(b);
-}
-
-long
-writeqrctl(char *b, long n){
+writeqrctl(char *b, long){
 	char *s;
-	char *sep = " 	";
+	char sep[7];
 
+	sprintf(sep, " \t\n\f\r\v");
 	for(s = strtok(b, sep); s != nil; s = strtok(nil, sep)){
 		if(strcmp(s, "bufsz") == 0)
 			bufsz = strtoul(strtok(nil, sep), nil, 0);
@@ -323,53 +315,18 @@
 	}
 
 	cpool = erealloc(cpool, nclients*sizeof(*cpool));
+	genqrctl();
 
-	return n;
+	return strlen(qrctl);
 }
 
 long
-readqctl(char **buf, Client *c){
-	char *b, r[1024];
+writeqctl(char *b, long n, int client){
+	Client *c;
+	char *s, sep[7];
 
-	b = ecalloc(bufsz);
-	sprintf(b,
-		"connect %s\n",
-		"timeout %i\n",
-		"umask %l",
-		c->addr, c->timeout, c->umask);
-	if(c->oio){
-		sprintf(r,
-			"Rapiversion %i\n"
-			"Rport %i\n"
-			"Rpid %i\n"
-			"Ripaddress %s\n"
-			"Rvendor %s\n"
-			"Rlanguage %s\n"
-			"Rversion %s\n"
-			"Rmachine %s\n"
-			"Rarch %s\n"
-			"Rproject %s\n"
-			"Rprocess %s\n"
-			"Ruser %s\n"
-			"Rtoken %s\n"
-			"Rdate %s\n"
-			"Rplatform %s\n",
-			c->Rapiversion, c->Rport, c->Rpid, c->Ripaddress,
-			c->Rvendor, c->Rlanguage, c->Rversion, c->Rmachine,
-			c->Rarch, c->Rproject, c->Rprocess, c->Ruser,
-			c->Rtoken, c->Rdate, c->Rplatform);
-		strcpy(b, r);
-	}
-
-	*buf = b;
-	return strlen(b);
-}
-
-long
-writeqctl(char *b, long n, Client *c){
-	char *s, *sep;
-
-	sep = " 	";
+	c = clientref(client);
+	sprintf(sep, " \t\n\f\r\v");
 	for(s = strtok(b, sep); s != nil; s = strtok(nil, sep)){
 		if(strcmp(s, "connect") == 0)
 			c->addr = estrdup(strtok(nil, sep));
@@ -379,20 +336,18 @@
 			c->umask = strtoul(strtok(nil, sep), nil, 0);
 	}
 
+	genqctl(client);
+
 	return n;
 }
 
 long
-readqio(char **buf, Client *c){
-	*buf = estrdup(c->pres);
-	return strlen(*buf);
-}
-
-long
-writeqio(char *b, long, Client *c){
+writeqio(char *b, long, int client){
+	Client *c;
 	char *pld, *e, *p, *z;
 	long sz;
 
+	c = clientref(client);
 	pld = z = ecalloc(bufsz);
 	e = pld + bufsz - 1;
 	sz = -1;
@@ -414,42 +369,53 @@
 }
 
 void
-mkdirent(Dir *d, int kind, Client *c){
-	char *nm, *buf;
+mkdirent(Dir *d, int kind, int client){
+	Client *c;
+	char *nm;
 
-	mkqid(&d->qid, kind, c);
+	memset(d, 0, sizeof(*d));
+	mkqid(&d->qid, kind, client);
 	d->mode = 0444 & umask;
 	if(nil != (nm = nametab[kind]))
-		d->name = nm;
+		d->name = estrdup(nm);
+	if(kind == Qclient){
+		nm = ecalloc(bufsz);
+		sprintf(nm, "%i", client);
+		d->name = estrdup(nm);
+	}
+	if(d->qid.type & QTDIR)
+		d->mode |= DMDIR | 0111;
 
-	buf = ecalloc(bufsz);
+	c = clientref(client);
 	switch(kind){
+	case Qrctl:   d->mode = 0666 & umask; break;
+	case Qctl:
+	case Qio:     d->mode = 0666 & c->umask; break;
+	}
+
+	switch(kind){
 	case Qroot:
-		d->mode = 0777 & umask;
 	case Qrctl:
+	case Qclone:
 		d->atime = d->mtime = time0;
 		d->uid = estrdup(user);
 		d->gid = estrdup(user);
 		d->muid = estrdup(user);
 		break;
-	case Qclient:
-		d->mode = 0777 & c->umask;
-		sprintf(buf, "%i", c->id);
-		d->name = estrdup(buf);
 	default:
 		d->atime = d->mtime = c->time0;
 		d->uid = estrdup(c->user);
 		d->gid = estrdup(c->user);
 		d->muid = estrdup(c->user);
+		break;
 	}
 
 	switch(kind){
-	case Qrctl: d->length = readqrctl(&buf);
-	case Qctl: d->length = readqctl(&buf, c);
-	case Qio: d->length = readqio(&buf, c);
+	case Qrctl: d->length = strlen(qrctl); break;
+	case Qctl: d->length = strlen(c->qctl); break;
+	case Qio: d->length = c->pres == nil ? 0 : strlen(c->pres); break;
+	case Qrinfo: d->length = c->rinfo == nil ? 0 : strlen(c->rinfo); break;
 	}
-
-	free(buf);
 }
 
 int
@@ -459,7 +425,7 @@
 
 	i += Qroot + 1;
 	if(i < Qclient){
-		mkdirent(d, i, nil);
+		mkdirent(d, i, -1);
 	} else {
 		i -= Qclient;
 		if(i == 0)
@@ -468,7 +434,7 @@
 		if(j == nclients)
 			return -1;
 		n++;
-		mkdirent(d, Qclient, clientref(j));
+		mkdirent(d, Qclient, j);
 	}
 
 	return 0;
@@ -476,26 +442,26 @@
 
 int
 genqclient(int i, Dir *d, void *aux){
-	Client *c;
+	int client;
 
-	c = aux;
+	client = (vlong)aux;
 	i += Qclient + 1;
 	if(i >= QCOUNT)
 		return -1;
-	mkdirent(d, i, c);
+	mkdirent(d, i, client);
 	return 0;
 }
 
-
 static void
 fsdestroyfid(Fid *fid){
 	Rfid *f;
 
 	f = fid->aux;
-	if(-1 < f->client){
-		rmclient(f->client);
-		free(f);
-	}
+	if(f == nil)
+		return;
+
+	rmclient(f->client);
+	free(f);
 }
 
 static void
@@ -513,11 +479,12 @@
 static void
 fsattach(Req *r){
 	Rfid *f;
-	
+
 	f = ecalloc(sizeof(*f));
 	f->kind = Qroot;
+	f->client = -1;
 
-	mkqid(&r->fid->qid, f->kind, nil);
+	mkqid(&r->fid->qid, f->kind, f->client);
 	r->fid->aux = f;
 	r->ofcall.qid = r->fid->qid;
 
@@ -542,9 +509,8 @@
 		}
 
 		f->kind = Qctl;
-		c = clientref(f->client);
 
-		mkqid(&r->ofcall.qid, f->kind, c);
+		mkqid(&r->ofcall.qid, f->kind, f->client);
 		r->fid->qid = r->ofcall.qid;
 
 		respond(r, nil);
@@ -574,6 +540,8 @@
 			c->iopid = pid;
 		}
 		break;
+	default:
+		respond(r, nil);
 	}
 }
 
@@ -582,23 +550,22 @@
 	Rfid *f;
 	Client *c;
 	char *buf;
-	long n;
 
 	buf = nil;
-	n = -1;
 	f = r->fid->aux;
 	c = clientref(f->client);
 	switch(f->kind){
 	case Qroot: dirread9p(r, genqroot, nil); break;
-	case Qrctl: n = readqrctl(&buf); break;
+	case Qrctl: buf = estrdup(qrctl); break;
 	case Qclone: respond(r, "read prohibited"); return;
-	case Qclient: dirread9p(r, genqclient, c); break;
-	case Qctl: n = readqctl(&buf, c); break;
-	case Qio: n = readqio(&buf, c); break;
+	case Qclient: dirread9p(r, genqclient, (void*)f->client); break;
+	case Qctl: buf = estrdup(c->qctl); break;
+	case Qio: buf = estrdup(c->pres); break;
+	case Qrinfo: buf = estrdup(c->rinfo); break;
 	}
 
 	if(buf != nil){
-		readbuf(r, buf, n);
+		readbuf(r, buf, strlen(buf));
 		free(buf);
 	}
 
@@ -610,28 +577,32 @@
 	Rfid *f;
 	Client *c;
 	int pid;
+	char *d, *err;
+	long n;
 
+	d = r->ifcall.data;
+	n = r->ifcall.count;
 	f = r->fid->aux;
 	c = clientref(f->client);
+	err = nil;
 
 	switch(f->kind){
 	case Qrctl:
-		r->ofcall.count = writeqrctl(r->ifcall.data, r->ifcall.count);
+		r->ofcall.count = writeqrctl(d, n);
 		break;
 	case Qctl:
-		r->ofcall.count = writeqctl(r->ifcall.data, r->ifcall.count, c);
+		r->ofcall.count = writeqctl(d, n, f->client);
 		break;
 	case Qio:
 		switch(pid = rfork(RFPROC|RFNOWAIT|RFMEM)){
 		case 0:
 			alarm(c->timeout);
-			r->ofcall.count = writeqio(r->ifcall.data, r->ifcall.count, c);
+			r->ofcall.count = writeqio(d, n, f->client);
 			alarm(0);
 			c->iopid = 0;
-			respond(r, nil);
 			break;
 		case -1:
-			respond(r, "failed to send command");
+			err = "failed to fork write";
 			break;
 		default:
 			c->iopid = pid;
@@ -638,18 +609,21 @@
 		}
 		break;
 	default:
-		respond(r, "write prohibited"); return;
+		err = "write prohibited";
 	}
+
+	respond(r, err);
 }
 
 static void
 fsflush(Req *r){
+	Req *o;
 	Rfid *f;
 	Client *c;
 
-	f = r->fid->aux;
-	c = clientref(f->client);
-
+	if(o = r->oldreq)
+	if(f = o->fid->aux)
+	if(c = clientref(f->client))
 	if(0 < c->iopid){
 		postnote(PNPROC, c->iopid, "interrupt");
 		respond(r, "interrupted");
@@ -661,11 +635,9 @@
 static void
 fsstat(Req *r){
 	Rfid *f;
-	Client *c;
 
 	f = r->fid->aux;
-	c = clientref(f->client);
-	mkdirent(&r->d, f->kind, c);
+	mkdirent(&r->d, f->kind, f->client);
 
 	respond(r, nil);
 }
@@ -700,9 +672,10 @@
 				break;
 			if(i == Qclient){
 				n = strtol(name, &nend, 10);
-				if(*nend == 0 && nil != (c = clientref(n)) && c->ref != 0){
-					f->client = n;
+				c = clientref(n);
+				if(*nend == 0 && c != nil && c->ref != 0){
 					incref(c);
+					f->client = n;
 					break;
 				}	
 			}
@@ -711,7 +684,7 @@
 			return "directory entry not found";
 		f->kind = i;
 	}
-	mkqid(qid, f->kind, clientref(n));
+	mkqid(qid, f->kind, n);
 	fid->qid = *qid;
 	return nil;
 }
@@ -727,7 +700,7 @@
 	f = ecalloc(sizeof(*f));
 	memmove(f, o, sizeof(*f));
 
-	if(-1 < f->client)
+	if(f->client > -1)
 		incref(clientref(f->client));
 	newfid->aux = f;
 
@@ -755,12 +728,13 @@
 
 void
 main(int argc, char **argv){
-	timeout = 10000;
+	user = getuser();
 	mtpt = "/mnt/ride";
-	bufsz = 4096;
 	umask = 0755;
+	bufsz = 4096;
 	time0 = time(0);
 	nclients = 256;
+	timeout = 10000;
 
 	ARGBEGIN{
 	case 'D': chatty9p++; break;
@@ -773,6 +747,23 @@
 	}ARGEND
 
 	cpool = ecalloc(nclients*sizeof(*cpool));
+	qrctl = ecalloc(bufsz);
+	genqrctl();
+
+	if(debug)
+		fprintf(stderr,
+			"ridefs:\n"
+			"\tchatty9p = %i\n"
+			"\tdebug = %i\n"
+			"\ttimeout = %i\n"
+			"\tmtpt = %s\n"
+			"\tservice = %s\n"
+			"\tnet = %s\n"
+			"\tfs = %p\n"
+			"\tcpool = %p\n",
+			chatty9p, debug, timeout,
+			mtpt, service, net,
+			&fs, cpool);
 
 	rfork(RFNOTEG);
 	postmountsrv(&fs, service, mtpt, MREPL);
--- /dev/null
+++ b/test
@@ -1,0 +1,51 @@
+#!/bin/rc
+
+fn fail{ echo $1; exit $1}
+
+./6.out $* ||
+	fail 'Crashed at startup'
+
+cd /mnt/ride ||
+	fail 'Not mounted'
+
+ls . >/dev/null ||
+	fail 'Mountpoint not readable'
+
+cat ctl >/dev/null ||
+	fail 'Could not read ctl'
+
+ot=`{grep timeout ctl}
+echo 'timeout 5000' >ctl ||
+	fail 'Could not write ctl'
+
+nt=`{grep timeout ctl}
+~ $nt(2) 5000 ||
+	fail 'Written and read ctl values differ'
+echo timeout $ot(2) >ctl
+
+cat clone >/dev/null ||
+	fail 'Could not clone'
+
+<clone {
+	cd `{read} ||
+		fail 'Could not cd to client'
+
+	cat ctl >/dev/null ||
+		fail 'Could not read client ctl'
+
+	ot=`{grep timeout ctl}
+	echo 'timeout 5000' >ctl ||
+		fail 'Could not write client ctl'
+
+	nt=`{grep timeout ctl}
+	~ $nt(2) 5000 ||
+		fail 'Written and read client ctl values differ'
+	echo timeout $ot(2) >ctl
+
+	cd .. ||
+		fail 'Could not cd out of client directory'
+}
+
+n=`{read clone}
+ls -d $n >[2]/dev/null &&
+	fail 'Did not clean up closed client'
--