hlfw.ca

registry

Download patch

ref: ce728ca7c437aceea271ee66d97fe4b819b4d39a
parent: 27ba384849a8ceb8f04a6180f7c1a7467e4ee466
author: halfwit <michaelmisch1985@gmail.com>
date: Thu Oct 12 11:06:41 PDT 2023

More svcfs work

--- a/README.md
+++ b/README.md
@@ -36,6 +36,8 @@
 `svcfs` manages the contents of a file, `/adm/services`, which it will read in on startup
 It serves up on mtpt, by default using `/mnt/services`
 
+A service can be added by creating a directory. Services may be read by anyone, but can only be modified by the creator or registry owner. Write requests must come from users in the same authdom.
+
 Each service dir contains many of the following files: 
  - addr
  - auth
@@ -43,8 +45,7 @@
  - uptime
  - description
 
-A service can be added by creating a directory. Services may be read by anyone, but can only be modified by the creator or registry owner. Write requests must come from users in the same authdom.
-
+### Notes
  - It may be beneficial to expose an events file that `services` can do a blocking read on, waiting for a service to be removed/added
  - `auth` is an optional address for the auth server to use
 
@@ -51,11 +52,12 @@
 ## svc/services 
 
 Usage: `svc/services [-o] [-f servicesdb] [-s svcfs]`
-- `-o` Alternate naming in services, `ipnet.sysname.service`
+
+- `-o` Alternate naming in services, `ipnet.sysname.svcname`
 - `-f` Read in services from db
 - `-s` Address of svcfs
 
-Registry connects to a `svcfs`, by default checking for an entry in your local ipnet=. 
+Services connects to a `svcfs`, by default checking for an entry in your local ipnet=. 
 Without `-f`, it checks for and parses `/cfg/$sysname/registry`. (`-f` and the default directroy are temporary stopgaps before services can be self-publishing)
 
 ```
@@ -78,7 +80,7 @@
 Query the svcfs for any services matching query. It returns a tuple for each match
 
 ```
-$ svcquery speakers
+$ svc/query speakers
 service=speakers addr=livingroom!12345 description='Living room speakers' uptime=1239021 status=ok
 service=speakers addr=bedroom!1234 description='Bedroom speakers' uptime=123811 status=ok
 ```
@@ -100,7 +102,6 @@
 Usage: `svc/update [-s svcfs] svcname [attr value]`
 
 This replaces the given attr/value pairs with the ones provided. This must be ran as the user who created the service entry, or the hostowner of `svcfs`.
-
 - `attr` can be one of `description` or `auth`
 
 ## Future
--- a/aux/svcfs.c
+++ b/aux/svcfs.c
@@ -5,8 +5,7 @@
 // fs
 //  - addr, description, status, etc in dir from backing. 
 //  - uptime from keepalive thread
-//  Every run, we check and set status + uptime
-// Auth? We mostly don't care about auth outside of creates, but this should be considered eventually
+// Every run, we check and set status + uptime
 
 typedef struct Fid Fid;
 typedef struct Service Service;
@@ -18,9 +17,11 @@
 	Qstatus,
 	Quptime,
 	Qdesc,
-	Qlog,
 
+	Namelen = 28,
 	Nsvcs = 512,
+	MAXDESC = 256,
+	MAXADDR = 128,
 };
 
 enum {
@@ -57,33 +58,32 @@
 	[Qstatus]	"status",
 	[Quptime]	"uptime",
 	[Qdesc]		"description",
-	[Qlog]		"log",
 };
 
 char *status[Smax] = {
 	[Sok] 	= "ok",
-	[Sdown]	= "offline",
+	[Sdown]	= "down",
 };
 
 Fid *fids;
 Service *services[Nsvcs];
 char	*svcfile;
-int	readonly;
+int		readonly;
 ulong	uniq;
 uchar	mdata[8192 + IOHDRSZ];
-int	messagesize = sizeof mdata;
+int		messagesize = sizeof mdata;
 
 Service *findsvc(char*);
 Service *installsvc(char*);
 void	insertsvc(Service*);
-int	removesvc(Service*);
-int	readservices(void);
-int	writeservices(void);
-int	dostat(Service*, ulong, void*, int);
+int		removesvc(Service*);
+int		readservices(void);
+int		writeservices(void);
+int		dostat(Service*, ulong, void*, int);
 void	io(int, int);
-Qid	mkqid(Service*, ulong);
+Qid		mkqid(Service*, ulong);
 ulong	hash(char*);
-Fid	*findfid(int);
+Fid		*findfid(int);
 void	*emalloc(ulong);
 char	*estrdup(char*);
 
@@ -422,9 +422,6 @@
 	case Qdesc:
 		sprint(data, "%s\n", f->svc->description);
 		goto Readstr;
-	case Qlog:
-		sprint(data, "%s\n", "TODO");
-		goto Readstr;
 	default:
 		return "permission denied";
 	}	
@@ -445,7 +442,7 @@
 	data = rhdr.data;
 	switch(f->qtype) {
 	case Qaddr:
-		if(n > 512)
+		if(n > MAXADDR)
 			return "address too big!";
 		memmove(f->svc->addr, data, n);
 		f->svc->addr[n] = '\0';
@@ -452,7 +449,7 @@
 		thdr.count = n;
 		break;
 	case Qdesc:
-		if(n > 1024)
+		if(n > MAXPATHLEN)
 			return "description too long";
 		memmove(f->svc->description, data, n);
 		f->svc->description[n] = '\0';
@@ -462,7 +459,6 @@
 	case Qsvc:
 	case Quptime:
 	case Qstatus:
-	case Qlog:
 	default:
 		return "permission denied";
 	}
@@ -572,9 +568,10 @@
 void
 writeservices(void)
 {
+	int entrylen;
 	int fd, ns, i;
 	Service *svc;
-	uchar *buf;
+	uchar *p, *buf;
 
 	if(readonly){
 		fprint(2, "attempted to write services to disk in a readonly system\n");
@@ -581,19 +578,127 @@
 		return;
 	}
 	
+	// Timestamp + status
+	entrylen = MAXPATHLEN + MAXADDR + MAXDESC + 4 + 1; 
 	/* Count our services */
-	for(i = 0; i < Nsvcs; i++){
+	for(i = 0; i < Nsvcs; i++)
 		for(svc = svcs[i]; svc != nil; svc = svc->link)
 			ns++;
-	}
 
+	/* Make a buffer large enough to hold each line */
+	buf = emalloc(su * entrylen);
+	p = buf;
+	for(i = 0; i < Nsvcs; i++)
+		for(svc = svcs[i]; svc !=nil; svc = svc->link){
+			strncpy((char *)p, svc->name, Namelen);
+			p += Namelen;
+			strncpy((char *)p, svc->description, MAXDESC);
+			p += MAXDESC;
+			strncpy((char *)p, svc->addr, MAXADDR);
+			p += MAXADDR;
+			*p++ = svc->status;
+			*p++ = svc->uptime;
+			*p++ = svc->uptime >> 8;
+			*p++ = svc->uptime >> 16;
+			*p++ = svc->uptime >> 24;
+		}
 	
+	fd = create(svcfile, OWRITE, 0666);
+	if(fd < 0){
+		fprint(2, "svcfs: can't write %s: %r\n", svcfile);
+		free(buf);
+		return;
+	}
+	if(write(fd, buf, p - buf) != (p - buf))
+		fprint(2, "svcfs: can't write %s: %r\n", svcfile);
+	close(fd);
+	free(buf);
 }
 
 int
+svcok(char *svc, int nu)
+{
+	int i, n, rv;
+	Rune r;
+	char buf[Namelen+1];
+
+	memset(buf, 0, sizeof buf);
+	memmove(buf, svc, MAXPATHLEN);
+
+	if(buf[Namelen-1] != 0){
+		fprint(2, "svcfs: %d: no termination: %W\n", nu, buf);
+		return -1;
+	}
+
+	rv = 0;
+	for(i = 0; buf[i]; i += n){
+		n = chartorune(&r, buf+i);
+		if(r == Runeerror){
+			rv = -1;
+		} else if(isascii(r) && iscntrl(r) || r == ' ' || r == '/'){
+			rv = -1;
+		}
+	}
+
+	if(i == 0){
+		fprint(2, "svcfs: %d: nil name\n", nu);
+		return -1;
+	}
+	if(rv == -1)
+		fprint(2, "svcfs: %d: bad syntax: %W\n", nu, buf);
+	return rv;
+}
+
+int
 readservices(void)
 {
-	//
+	int fd, i, n, ns;
+	uchar *p, *buf, *ep;
+	Service *svc;
+	Dir *d;
+
+	/* Read our file into buf */
+	fd = open(svcfile, OREAD);
+	if(fd < 0){
+		fprint(2, "svcfs: can't read %s: %r\n", svcfile);
+		return;
+	}
+	d = dirfstat(fd);
+	if(d == nil){
+		close(fd);
+		return;
+	}
+	buf = emalloc(d->length);
+	n = readn(fd, buf, d->length);
+	close(fd);
+	free(d);
+	if(n != d->length){
+		free(buf);
+		return 0;
+	}
+	// Timestamp + status
+	entrylen = MAXPATHLEN + MAXADDR + MAXDESC + 4 + 1; 
+	n = n / entrylen;
+	ns = 0;
+	for(i = 0; i < n; ep += entrylen, i++){
+		if(svcok((char *)ep, i) < 0)
+			continue;
+		svc = findsvc((char *)ep);
+		if(svc == nil)
+			svc = installsvc((char *)ep);
+		memmove(svc->description, ep + MAXPATHLEN, MAXDESC);
+		memmove(svc->addr, ep + MAXPATHLEN + MAXDESC, MAXADDR);
+		p = ep + MAXPATHLEN + MAXDESC + MAXADDR;
+		
+		svc->status = *p++;
+		if(svc->status >= Smax)
+			fprint(2, "svcfs: warning: bad status in key file\n");
+		svc->expire = p[0] + (p[1]<<8) + (p[2]<<16) + (p[3]<<24);
+		ns++;
+	}
+	free(buf);
+
+	print("%d services read in\n", ns);
 	return 1;
 }
 
--- a/svc/add
+++ b/svc/add
@@ -1,1 +1,2 @@
 #!/bin/rc
+
--- a/svc/services
+++ b/svc/services
@@ -1,2 +1,47 @@
 #!/bin/rc
 
+$argv0 = $0
+
+fn usage {
+    echo 'Usage:' $argv0 '[-o] [-f servicesdb] [-s svcfs]' >[1=2]
+    exits 'usage'
+}
+
+dbfile=()
+svcfs=()
+order=1
+while(~ $1 -*){
+	switch($1){
+	case -o; order=2
+	case *
+		~ $#* 1 && usage
+		switch($1){
+		case -f; dbfile=$2
+		case -s; svcfs=$2
+		case *; usage
+		}
+		shift
+	}
+	shift
+}
+
+! ~ $#* 0 && usage
+
+if(~ $svcfs "")
+	svcfs=`{ndb/ipquery sys $sysname registry | sed 's/registry=//'}
+if(~ $svcfs ""){
+	echo 'Unable to find Registry'
+	exits 'registry'
+}
+# Ours, we check later for the one associated with svcfs
+ipnet=`{ndb/ipquery sys $sysname ipnet | sed 's/ipnet=//'}
+
+# Connect to svcfs
+# Initial writes
+# Initial read + post everything
+#  - if we posted the service, service.local
+# Try /cfg/sysname/services if not set
+# Walk the dir, parse addr file + build /srv/service.sysname.ipnet
+# With -o, /srv/ipnet.sysname.service
+# Lookup our own ipnet
+# With -s, parse the addr ipnet if exists and use that instead
\ No newline at end of file