429 lines
6.9 KiB
C
429 lines
6.9 KiB
C
![]() |
#include <u.h>
|
||
|
#include <libc.h>
|
||
|
#include "plumb.h"
|
||
|
|
||
|
static char attrbuf[4096];
|
||
|
|
||
|
int
|
||
|
plumbopen(char *name, int omode)
|
||
|
{
|
||
|
int fd, f;
|
||
|
char *s, *plumber;
|
||
|
char buf[128], err[ERRMAX];
|
||
|
|
||
|
if(name[0] == '/')
|
||
|
return open(name, omode);
|
||
|
|
||
|
/* find elusive plumber */
|
||
|
if(access("/mnt/plumb/send", AWRITE) >= 0)
|
||
|
plumber = "/mnt/plumb";
|
||
|
else if(access("/mnt/term/mnt/plumb/send", AWRITE) >= 0)
|
||
|
plumber = "/mnt/term/mnt/plumb";
|
||
|
else{
|
||
|
/* last resort: try mounting service */
|
||
|
plumber = "/mnt/plumb";
|
||
|
s = getenv("plumbsrv");
|
||
|
if(s == nil)
|
||
|
return -1;
|
||
|
f = open(s, ORDWR);
|
||
|
free(s);
|
||
|
if(f < 0)
|
||
|
return -1;
|
||
|
if(mount(f, -1, "/mnt/plumb", MREPL, "") < 0){
|
||
|
close(f);
|
||
|
return -1;
|
||
|
}
|
||
|
if(access("/mnt/plumb/send", AWRITE) < 0)
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
snprint(buf, sizeof buf, "%s/%s", plumber, name);
|
||
|
fd = open(buf, omode);
|
||
|
if(fd >= 0)
|
||
|
return fd;
|
||
|
|
||
|
/* try creating port; used by non-standard plumb implementations */
|
||
|
rerrstr(err, sizeof err);
|
||
|
fd = create(buf, omode, 0600);
|
||
|
if(fd >= 0)
|
||
|
return fd;
|
||
|
errstr(err, sizeof err);
|
||
|
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
|
||
|
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);
|
||
|
i = plumbline(&ntext, buf, i, n, &bad);
|
||
|
if(bad){
|
||
|
plumbfree(m);
|
||
|
return nil;
|
||
|
}
|
||
|
m->attr = plumbunpackattr(attr);
|
||
|
free(attr);
|
||
|
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;
|
||
|
}
|