Single-threaded plumber that can run "start" rules.
Thanks to Caerwyn Jones.
This commit is contained in:
parent
169aba14a4
commit
3d7e9092a4
8 changed files with 731 additions and 2 deletions
48
include/plumb.h
Normal file
48
include/plumb.h
Normal 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
16
src/cmd/plumb/Makefile
Normal 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
|
||||||
|
|
@ -7,6 +7,8 @@ OFILES=\
|
||||||
_exits.$O\
|
_exits.$O\
|
||||||
argv0.$O\
|
argv0.$O\
|
||||||
await.$O\
|
await.$O\
|
||||||
|
cleanname.$O\
|
||||||
|
dirstat.$O\
|
||||||
encodefmt.$O\
|
encodefmt.$O\
|
||||||
errstr.$O\
|
errstr.$O\
|
||||||
exits.$O\
|
exits.$O\
|
||||||
|
|
@ -16,12 +18,10 @@ OFILES=\
|
||||||
lock.$O\
|
lock.$O\
|
||||||
malloctag.$O\
|
malloctag.$O\
|
||||||
mallocz.$O\
|
mallocz.$O\
|
||||||
netmkaddr.$O\
|
|
||||||
nrand.$O\
|
nrand.$O\
|
||||||
qlock.$O\
|
qlock.$O\
|
||||||
readn.$O\
|
readn.$O\
|
||||||
rendez-$(SYSNAME).$O\
|
rendez-$(SYSNAME).$O\
|
||||||
sleep.$O\
|
|
||||||
strecpy.$O\
|
strecpy.$O\
|
||||||
sysfatal.$O\
|
sysfatal.$O\
|
||||||
tas-$(OBJTYPE).$O\
|
tas-$(OBJTYPE).$O\
|
||||||
|
|
|
||||||
52
src/lib9/cleanname.c
Normal file
52
src/lib9/cleanname.c
Normal 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
83
src/lib9/dirstat.c
Normal 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
19
src/libplumb/Makefile
Executable 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
108
src/libplumb/event.c
Executable 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
403
src/libplumb/mesg.c
Executable 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;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue