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