Single-threaded plumber that can run "start" rules.

Thanks to Caerwyn Jones.
This commit is contained in:
rsc 2003-10-14 02:35:00 +00:00
parent 169aba14a4
commit 3d7e9092a4
8 changed files with 731 additions and 2 deletions

48
include/plumb.h Normal file
View file

@ -0,0 +1,48 @@
#pragma lib "libplumb.a"
#pragma src "/sys/src/libplumb"
/*
* Message format:
* source application\n
* destination port\n
* working directory\n
* type\n
* attributes\n
* nbytes\n
* n bytes of data
*/
typedef struct Plumbattr Plumbattr;
typedef struct Plumbmsg Plumbmsg;
struct Plumbmsg
{
char *src;
char *dst;
char *wdir;
char *type;
Plumbattr *attr;
int ndata;
char *data;
};
struct Plumbattr
{
char *name;
char *value;
Plumbattr *next;
};
int plumbsend(int, Plumbmsg*);
Plumbmsg* plumbrecv(int);
char* plumbpack(Plumbmsg*, int*);
Plumbmsg* plumbunpack(char*, int);
Plumbmsg* plumbunpackpartial(char*, int, int*);
char* plumbpackattr(Plumbattr*);
Plumbattr* plumbunpackattr(char*);
Plumbattr* plumbaddattr(Plumbattr*, Plumbattr*);
Plumbattr* plumbdelattr(Plumbattr*, char*);
void plumbfree(Plumbmsg*);
char* plumblookup(Plumbattr*, char*);
int plumbopen(char*, int);
int eplumb(int, char*);

16
src/cmd/plumb/Makefile Normal file
View file

@ -0,0 +1,16 @@
CFLAGS=-I../../../include
LDLIBS=-L../../../lib -lplumb -lbio -lregexp9 -lfmt -l9 -lutf
all: plumb plumber
plumb: plumb.o
cc -o $@ plumb.o $(LDLIBS)
plumber: match.o rules.o plumber.o
cc -o $@ match.o rules.o plumber.o $(LDLIBS)
clean:
rm -f *.o
install: plumb plumber
cp plumb plumber ../../../bin

View file

@ -7,6 +7,8 @@ OFILES=\
_exits.$O\
argv0.$O\
await.$O\
cleanname.$O\
dirstat.$O\
encodefmt.$O\
errstr.$O\
exits.$O\
@ -16,12 +18,10 @@ OFILES=\
lock.$O\
malloctag.$O\
mallocz.$O\
netmkaddr.$O\
nrand.$O\
qlock.$O\
readn.$O\
rendez-$(SYSNAME).$O\
sleep.$O\
strecpy.$O\
sysfatal.$O\
tas-$(OBJTYPE).$O\

52
src/lib9/cleanname.c Normal file
View file

@ -0,0 +1,52 @@
#include <u.h>
#include <libc.h>
/*
* In place, rewrite name to compress multiple /, eliminate ., and process ..
*/
#define SEP(x) ((x)=='/' || (x) == 0)
char*
cleanname(char *name)
{
char *p, *q, *dotdot;
int rooted;
rooted = name[0] == '/';
/*
* invariants:
* p points at beginning of path element we're considering.
* q points just past the last path element we wrote (no slash).
* dotdot points just past the point where .. cannot backtrack
* any further (no slash).
*/
p = q = dotdot = name+rooted;
while(*p) {
if(p[0] == '/') /* null element */
p++;
else if(p[0] == '.' && SEP(p[1]))
p += 1; /* don't count the separator in case it is nul */
else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) {
p += 2;
if(q > dotdot) { /* can backtrack */
while(--q > dotdot && *q != '/')
;
} else if(!rooted) { /* /.. is / but ./../ is .. */
if(q != name)
*q++ = '/';
*q++ = '.';
*q++ = '.';
dotdot = q;
}
} else { /* real path element */
if(q != name+rooted)
*q++ = '/';
while((*q = *p) != '/' && *q != 0)
p++, q++;
}
}
if(q == name) /* empty string is really ``.'' */
*q++ = '.';
*q = '\0';
return name;
}

83
src/lib9/dirstat.c Normal file
View file

@ -0,0 +1,83 @@
#include "u.h"
#include "libc.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <grp.h>
static void
statconv(Dir *dir, struct stat *s)
{
struct passwd *p;
struct group *g;
ulong q;
p = getpwuid(s->st_uid);
if (p)
strncpy(dir->uid, p->pw_name, NAMELEN);
g = getgrgid(s->st_gid);
if (g)
strncpy(dir->gid, g->gr_name, NAMELEN);
q = 0;
if(S_ISDIR(s->st_mode))
q = CHDIR;
q |= s->st_ino & 0x00FFFFFFUL;
dir->qid.path = q;
dir->qid.vers = s->st_mtime;
dir->mode = (dir->qid.path&CHDIR)|(s->st_mode&0777);
dir->atime = s->st_atime;
dir->mtime = s->st_mtime;
dir->length = s->st_size;
dir->dev = s->st_dev;
dir->type = 'M';
if(S_ISFIFO(s->st_mode))
dir->type = '|';
}
int
dirfstat(int fd, Dir *d)
{
struct stat sbuf;
if(fstat(fd, &sbuf) < 0)
return -1;
statconv(d, &sbuf);
return 0;
}
static char *
lelem(char *path)
{
char *pr;
pr = utfrrune(path, '/');
if(pr)
pr++;
else
pr = path;
return pr;
}
int
dirstat(char *f, Dir *d)
{
struct stat sbuf;
if(stat(f, &sbuf) < 0)
return -1;
statconv(d, &sbuf);
strncpy(d->name, lelem(f), NAMELEN);
return 0;
}
int
dirfwstat(int fd, Dir *d)
{
return -1;
}
int
dirwstat(char *name, Dir *d)
{
return -1;
}

19
src/libplumb/Makefile Executable file
View file

@ -0,0 +1,19 @@
LIB=../../lib/libplumb.a
OFILES=\
mesg.o\
HFILES=../../include/plumb.h
INCLUDES=-I../../include
CFLAGS += $(INCLUDES) -D_POSIX_SOURCE
CC=cc
$(LIB): $(OFILES)
ar r $(LIB) $(OFILES)
clean:
rm -rf $(TARG) $(OFILES)

108
src/libplumb/event.c Executable file
View file

@ -0,0 +1,108 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include "plumb.h"
typedef struct EQueue EQueue;
struct EQueue
{
int id;
char *buf;
int nbuf;
EQueue *next;
};
static EQueue *equeue;
static Lock eqlock;
static
int
partial(int id, Event *e, uchar *b, int n)
{
EQueue *eq, *p;
int nmore;
lock(&eqlock);
for(eq = equeue; eq != nil; eq = eq->next)
if(eq->id == id)
break;
unlock(&eqlock);
if(eq == nil)
return 0;
/* partial message exists for this id */
eq->buf = realloc(eq->buf, eq->nbuf+n);
if(eq->buf == nil)
drawerror(display, "eplumb: cannot allocate buffer");
memmove(eq->buf+eq->nbuf, b, n);
eq->nbuf += n;
e->v = plumbunpackpartial((char*)eq->buf, eq->nbuf, &nmore);
if(nmore == 0){ /* no more to read in this message */
lock(&eqlock);
if(eq == equeue)
equeue = eq->next;
else{
for(p = equeue; p!=nil && p->next!=eq; p = p->next)
;
if(p == nil)
drawerror(display, "eplumb: bad event queue");
p->next = eq->next;
}
unlock(&eqlock);
free(eq->buf);
free(eq);
}
return 1;
}
static
void
addpartial(int id, char *b, int n)
{
EQueue *eq;
eq = malloc(sizeof(EQueue));
if(eq == nil)
return;
eq->id = id;
eq->nbuf = n;
eq->buf = malloc(n);
if(eq->buf == nil){
free(eq);
return;
}
memmove(eq->buf, b, n);
lock(&eqlock);
eq->next = equeue;
equeue = eq;
unlock(&eqlock);
}
static
int
plumbevent(int id, Event *e, uchar *b, int n)
{
int nmore;
if(partial(id, e, b, n) == 0){
/* no partial message already waiting for this id */
e->v = plumbunpackpartial((char*)b, n, &nmore);
if(nmore > 0) /* incomplete message */
addpartial(id, (char*)b, n);
}
if(e->v == nil)
return 0;
return id;
}
int
eplumb(int key, char *port)
{
int fd;
fd = plumbopen(port, OREAD|OCEXEC);
if(fd < 0)
return -1;
return estartfn(key, fd, 8192, plumbevent);
}

403
src/libplumb/mesg.c Executable file
View file

@ -0,0 +1,403 @@
#include <u.h>
#include <libc.h>
#include "plumb.h"
static char attrbuf[4096];
int
plumbopen(char *name, int omode)
{
int fd, f;
char *s;
char buf[128];
if(name[0] == '/')
return open(name, omode);
snprint(buf, sizeof buf, "/mnt/plumb/%s", name);
fd = open(buf, omode);
if(fd >= 0)
return fd;
snprint(buf, sizeof buf, "/mnt/term/mnt/plumb/%s", name);
fd = open(buf, omode);
if(fd >= 0)
return fd;
/* try mounting service */
s = getenv("plumbsrv");
if(s == nil)
return -1;
snprint(buf, sizeof buf, "/mnt/plumb/%s", name);
return open(buf, omode);
}
static int
Strlen(char *s)
{
if(s == nil)
return 0;
return strlen(s);
}
static char*
Strcpy(char *s, char *t)
{
if(t == nil)
return s;
return strcpy(s, t) + strlen(t);
}
/* quote attribute value, if necessary */
static char*
quote(char *s)
{
char *t;
int c;
if(s == nil){
attrbuf[0] = '\0';
return attrbuf;
}
if(strpbrk(s, " '=\t") == nil)
return s;
t = attrbuf;
*t++ = '\'';
while(t < attrbuf+sizeof attrbuf-2){
c = *s++;
if(c == '\0')
break;
*t++ = c;
if(c == '\'')
*t++ = c;
}
*t++ = '\'';
*t = '\0';
return attrbuf;
}
char*
plumbpackattr(Plumbattr *attr)
{
int n;
Plumbattr *a;
char *s, *t;
if(attr == nil)
return nil;
n = 0;
for(a=attr; a!=nil; a=a->next)
n += Strlen(a->name) + 1 + Strlen(quote(a->value)) + 1;
s = malloc(n);
if(s == nil)
return nil;
t = s;
*t = '\0';
for(a=attr; a!=nil; a=a->next){
if(t != s)
*t++ = ' ';
strcpy(t, a->name);
strcat(t, "=");
strcat(t, quote(a->value));
t += strlen(t);
}
if(t > s+n)
abort();
return s;
}
char*
plumblookup(Plumbattr *attr, char *name)
{
while(attr){
if(strcmp(attr->name, name) == 0)
return attr->value;
attr = attr->next;
}
return nil;
}
char*
plumbpack(Plumbmsg *m, int *np)
{
int n, ndata;
char *buf, *p, *attr;
ndata = m->ndata;
if(ndata < 0)
ndata = Strlen(m->data);
attr = plumbpackattr(m->attr);
n = Strlen(m->src)+1 + Strlen(m->dst)+1 + Strlen(m->wdir)+1 +
Strlen(m->type)+1 + Strlen(attr)+1 + 16 + ndata;
buf = malloc(n+1); /* +1 for '\0' */
if(buf == nil){
free(attr);
return nil;
}
p = Strcpy(buf, m->src);
*p++ = '\n';
p = Strcpy(p, m->dst);
*p++ = '\n';
p = Strcpy(p, m->wdir);
*p++ = '\n';
p = Strcpy(p, m->type);
*p++ = '\n';
p = Strcpy(p, attr);
*p++ = '\n';
p += sprint(p, "%d\n", ndata);
memmove(p, m->data, ndata);
*np = (p-buf)+ndata;
buf[*np] = '\0'; /* null terminate just in case */
if(*np >= n+1)
abort();
free(attr);
return buf;
}
int
plumbsend(int fd, Plumbmsg *m)
{
char *buf;
int n;
buf = plumbpack(m, &n);
if(buf == nil)
return -1;
n = write(fd, buf, n);
free(buf);
return n;
}
static int
plumbline(char **linep, char *buf, int i, int n, int *bad)
{
int starti;
char *p;
if(*bad)
return i;
starti = i;
while(i<n && buf[i]!='\n')
i++;
if(i == n)
*bad = 1;
else{
p = malloc((i-starti) + 1);
if(p == nil)
*bad = 1;
else{
memmove(p, buf+starti, i-starti);
p[i-starti] = '\0';
}
*linep = p;
i++;
}
return i;
}
void
plumbfree(Plumbmsg *m)
{
Plumbattr *a, *next;
free(m->src);
free(m->dst);
free(m->wdir);
free(m->type);
for(a=m->attr; a!=nil; a=next){
next = a->next;
free(a->name);
free(a->value);
free(a);
}
free(m->data);
free(m);
}
Plumbattr*
plumbunpackattr(char *p)
{
Plumbattr *attr, *prev, *a;
char *q, *v;
int c, quoting;
attr = prev = nil;
while(*p!='\0' && *p!='\n'){
while(*p==' ' || *p=='\t')
p++;
if(*p == '\0')
break;
for(q=p; *q!='\0' && *q!='\n' && *q!=' ' && *q!='\t'; q++)
if(*q == '=')
break;
if(*q != '=')
break; /* malformed attribute */
a = malloc(sizeof(Plumbattr));
if(a == nil)
break;
a->name = malloc(q-p+1);
if(a->name == nil){
free(a);
break;
}
memmove(a->name, p, q-p);
a->name[q-p] = '\0';
/* process quotes in value */
q++; /* skip '=' */
v = attrbuf;
quoting = 0;
while(*q!='\0' && *q!='\n'){
if(v >= attrbuf+sizeof attrbuf)
break;
c = *q++;
if(quoting){
if(c == '\''){
if(*q == '\'')
q++;
else{
quoting = 0;
continue;
}
}
}else{
if(c==' ' || c=='\t')
break;
if(c == '\''){
quoting = 1;
continue;
}
}
*v++ = c;
}
a->value = malloc(v-attrbuf+1);
if(a->value == nil){
free(a->name);
free(a);
break;
}
memmove(a->value, attrbuf, v-attrbuf);
a->value[v-attrbuf] = '\0';
a->next = nil;
if(prev == nil)
attr = a;
else
prev->next = a;
prev = a;
p = q;
}
return attr;
}
Plumbattr*
plumbaddattr(Plumbattr *attr, Plumbattr *new)
{
Plumbattr *l;
l = attr;
if(l == nil)
return new;
while(l->next != nil)
l = l->next;
l->next = new;
return attr;
}
Plumbattr*
plumbdelattr(Plumbattr *attr, char *name)
{
Plumbattr *l, *prev;
prev = nil;
for(l=attr; l!=nil; l=l->next){
if(strcmp(name, l->name) == 0)
break;
prev = l;
}
if(l == nil)
return nil;
if(prev)
prev->next = l->next;
else
attr = l->next;
free(l->name);
free(l->value);
free(l);
return attr;
}
Plumbmsg*
plumbunpackpartial(char *buf, int n, int *morep)
{
Plumbmsg *m;
int i, bad;
char *ntext, *attr;
m = malloc(sizeof(Plumbmsg));
if(m == nil)
return nil;
memset(m, 0, sizeof(Plumbmsg));
if(morep != nil)
*morep = 0;
bad = 0;
i = plumbline(&m->src, buf, 0, n, &bad);
i = plumbline(&m->dst, buf, i, n, &bad);
i = plumbline(&m->wdir, buf, i, n, &bad);
i = plumbline(&m->type, buf, i, n, &bad);
i = plumbline(&attr, buf, i, n, &bad);
m->attr = plumbunpackattr(attr);
free(attr);
i = plumbline(&ntext, buf, i, n, &bad);
m->ndata = atoi(ntext);
if(m->ndata != n-i){
bad = 1;
if(morep!=nil && m->ndata>n-i)
*morep = m->ndata - (n-i);
}
free(ntext);
if(!bad){
m->data = malloc(n-i+1); /* +1 for '\0' */
if(m->data == nil)
bad = 1;
else{
memmove(m->data, buf+i, m->ndata);
m->ndata = n-i;
/* null-terminate in case it's text */
m->data[m->ndata] = '\0';
}
}
if(bad){
plumbfree(m);
m = nil;
}
return m;
}
Plumbmsg*
plumbunpack(char *buf, int n)
{
return plumbunpackpartial(buf, n, nil);
}
Plumbmsg*
plumbrecv(int fd)
{
char *buf;
Plumbmsg *m;
int n, more;
buf = malloc(8192);
if(buf == nil)
return nil;
n = read(fd, buf, 8192);
m = nil;
if(n > 0){
m = plumbunpackpartial(buf, n, &more);
if(m==nil && more>0){
/* we now know how many more bytes to read for complete message */
buf = realloc(buf, n+more);
if(buf == nil)
return nil;
if(readn(fd, buf+n, more) == more)
m = plumbunpackpartial(buf, n+more, nil);
}
}
free(buf);
return m;
}