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\
|
||||
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
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