Blob
1 #include <u.h>2 #include <libc.h>3 #include <fcall.h>4 #include <fs.h>5 #include "plumb.h"7 static char attrbuf[4096];9 char *home;10 static Fsys *fsplumb;11 static int pfd = -1;12 static Fid *pfid;13 int14 plumbopen(char *name, int omode)15 {16 int fd;18 if(fsplumb == nil)19 fsplumb = nsmount("plumb", "");20 if(fsplumb == nil)21 return -1;22 /*23 * It's important that when we send something,24 * we find out whether it was a valid plumb write.25 * (If it isn't, the client might fall back to some26 * other mechanism or indicate to the user what happened.)27 * We can't use a pipe for this, so we have to use the28 * fid interface. But we need to return a fd.29 * Return a fd for /dev/null so that we return a unique30 * file descriptor. In plumbsend we'll look for pfd31 * and use the recorded fid instead.32 */33 if((omode&3) == OWRITE){34 if(pfd != -1){35 werrstr("already have plumb send open");36 return -1;37 }38 pfd = open("/dev/null", OWRITE);39 if(pfd < 0)40 return -1;41 pfid = fsopen(fsplumb, name, omode);42 if(pfid == nil){43 close(pfd);44 pfd = -1;45 return -1;46 }47 return pfd;48 }50 fd = fsopenfd(fsplumb, name, omode);51 return fd;52 }54 int55 plumbsend(int fd, Plumbmsg *m)56 {57 char *buf;58 int n;60 if(fd != pfd){61 werrstr("fd is not the plumber");62 return -1;63 }64 buf = plumbpack(m, &n);65 if(buf == nil)66 return -1;67 n = fswrite(pfid, buf, n);68 free(buf);69 return n;70 }72 static int73 Strlen(char *s)74 {75 if(s == nil)76 return 0;77 return strlen(s);78 }80 static char*81 Strcpy(char *s, char *t)82 {83 if(t == nil)84 return s;85 return strcpy(s, t) + strlen(t);86 }88 /* quote attribute value, if necessary */89 static char*90 quote(char *s)91 {92 char *t;93 int c;95 if(s == nil){96 attrbuf[0] = '\0';97 return attrbuf;98 }99 if(strpbrk(s, " '=\t") == nil)100 return s;101 t = attrbuf;102 *t++ = '\'';103 while(t < attrbuf+sizeof attrbuf-2){104 c = *s++;105 if(c == '\0')106 break;107 *t++ = c;108 if(c == '\'')109 *t++ = c;110 }111 *t++ = '\'';112 *t = '\0';113 return attrbuf;114 }116 char*117 plumbpackattr(Plumbattr *attr)118 {119 int n;120 Plumbattr *a;121 char *s, *t;123 if(attr == nil)124 return nil;125 n = 0;126 for(a=attr; a!=nil; a=a->next)127 n += Strlen(a->name) + 1 + Strlen(quote(a->value)) + 1;128 s = malloc(n);129 if(s == nil)130 return nil;131 t = s;132 *t = '\0';133 for(a=attr; a!=nil; a=a->next){134 if(t != s)135 *t++ = ' ';136 strcpy(t, a->name);137 strcat(t, "=");138 strcat(t, quote(a->value));139 t += strlen(t);140 }141 if(t > s+n)142 abort();143 return s;144 }146 char*147 plumblookup(Plumbattr *attr, char *name)148 {149 while(attr){150 if(strcmp(attr->name, name) == 0)151 return attr->value;152 attr = attr->next;153 }154 return nil;155 }157 char*158 plumbpack(Plumbmsg *m, int *np)159 {160 int n, ndata;161 char *buf, *p, *attr;163 ndata = m->ndata;164 if(ndata < 0)165 ndata = Strlen(m->data);166 attr = plumbpackattr(m->attr);167 n = Strlen(m->src)+1 + Strlen(m->dst)+1 + Strlen(m->wdir)+1 +168 Strlen(m->type)+1 + Strlen(attr)+1 + 16 + ndata;169 buf = malloc(n+1); /* +1 for '\0' */170 if(buf == nil){171 free(attr);172 return nil;173 }174 p = Strcpy(buf, m->src);175 *p++ = '\n';176 p = Strcpy(p, m->dst);177 *p++ = '\n';178 p = Strcpy(p, m->wdir);179 *p++ = '\n';180 p = Strcpy(p, m->type);181 *p++ = '\n';182 p = Strcpy(p, attr);183 *p++ = '\n';184 p += sprint(p, "%d\n", ndata);185 memmove(p, m->data, ndata);186 *np = (p-buf)+ndata;187 buf[*np] = '\0'; /* null terminate just in case */188 if(*np >= n+1)189 abort();190 free(attr);191 return buf;192 }194 static int195 plumbline(char **linep, char *buf, int i, int n, int *bad)196 {197 int starti;198 char *p;200 if(*bad)201 return i;202 starti = i;203 while(i<n && buf[i]!='\n')204 i++;205 if(i == n)206 *bad = 1;207 else{208 p = malloc((i-starti) + 1);209 if(p == nil)210 *bad = 1;211 else{212 memmove(p, buf+starti, i-starti);213 p[i-starti] = '\0';214 }215 *linep = p;216 i++;217 }218 return i;219 }221 void222 plumbfree(Plumbmsg *m)223 {224 Plumbattr *a, *next;226 free(m->src);227 free(m->dst);228 free(m->wdir);229 free(m->type);230 for(a=m->attr; a!=nil; a=next){231 next = a->next;232 free(a->name);233 free(a->value);234 free(a);235 }236 free(m->data);237 free(m);238 }240 Plumbattr*241 plumbunpackattr(char *p)242 {243 Plumbattr *attr, *prev, *a;244 char *q, *v;245 int c, quoting;247 attr = prev = nil;248 while(*p!='\0' && *p!='\n'){249 while(*p==' ' || *p=='\t')250 p++;251 if(*p == '\0')252 break;253 for(q=p; *q!='\0' && *q!='\n' && *q!=' ' && *q!='\t'; q++)254 if(*q == '=')255 break;256 if(*q != '=')257 break; /* malformed attribute */258 a = malloc(sizeof(Plumbattr));259 if(a == nil)260 break;261 a->name = malloc(q-p+1);262 if(a->name == nil){263 free(a);264 break;265 }266 memmove(a->name, p, q-p);267 a->name[q-p] = '\0';268 /* process quotes in value */269 q++; /* skip '=' */270 v = attrbuf;271 quoting = 0;272 while(*q!='\0' && *q!='\n'){273 if(v >= attrbuf+sizeof attrbuf)274 break;275 c = *q++;276 if(quoting){277 if(c == '\''){278 if(*q == '\'')279 q++;280 else{281 quoting = 0;282 continue;283 }284 }285 }else{286 if(c==' ' || c=='\t')287 break;288 if(c == '\''){289 quoting = 1;290 continue;291 }292 }293 *v++ = c;294 }295 a->value = malloc(v-attrbuf+1);296 if(a->value == nil){297 free(a->name);298 free(a);299 break;300 }301 memmove(a->value, attrbuf, v-attrbuf);302 a->value[v-attrbuf] = '\0';303 a->next = nil;304 if(prev == nil)305 attr = a;306 else307 prev->next = a;308 prev = a;309 p = q;310 }311 return attr;312 }314 Plumbattr*315 plumbaddattr(Plumbattr *attr, Plumbattr *new)316 {317 Plumbattr *l;319 l = attr;320 if(l == nil)321 return new;322 while(l->next != nil)323 l = l->next;324 l->next = new;325 return attr;326 }328 Plumbattr*329 plumbdelattr(Plumbattr *attr, char *name)330 {331 Plumbattr *l, *prev;333 prev = nil;334 for(l=attr; l!=nil; l=l->next){335 if(strcmp(name, l->name) == 0)336 break;337 prev = l;338 }339 if(l == nil)340 return nil;341 if(prev)342 prev->next = l->next;343 else344 attr = l->next;345 free(l->name);346 free(l->value);347 free(l);348 return attr;349 }351 Plumbmsg*352 plumbunpackpartial(char *buf, int n, int *morep)353 {354 Plumbmsg *m;355 int i, bad;356 char *ntext, *attr;358 m = malloc(sizeof(Plumbmsg));359 if(m == nil)360 return nil;361 memset(m, 0, sizeof(Plumbmsg));362 if(morep != nil)363 *morep = 0;364 bad = 0;365 i = plumbline(&m->src, buf, 0, n, &bad);366 i = plumbline(&m->dst, buf, i, n, &bad);367 i = plumbline(&m->wdir, buf, i, n, &bad);368 i = plumbline(&m->type, buf, i, n, &bad);369 i = plumbline(&attr, buf, i, n, &bad);370 m->attr = plumbunpackattr(attr);371 free(attr);372 i = plumbline(&ntext, buf, i, n, &bad);373 m->ndata = atoi(ntext);374 if(m->ndata != n-i){375 bad = 1;376 if(morep!=nil && m->ndata>n-i)377 *morep = m->ndata - (n-i);378 }379 free(ntext);380 if(!bad){381 m->data = malloc(n-i+1); /* +1 for '\0' */382 if(m->data == nil)383 bad = 1;384 else{385 memmove(m->data, buf+i, m->ndata);386 m->ndata = n-i;387 /* null-terminate in case it's text */388 m->data[m->ndata] = '\0';389 }390 }391 if(bad){392 plumbfree(m);393 m = nil;394 }395 return m;396 }398 Plumbmsg*399 plumbunpack(char *buf, int n)400 {401 return plumbunpackpartial(buf, n, nil);402 }404 Plumbmsg*405 plumbrecv(int fd)406 {407 char *buf;408 Plumbmsg *m;409 int n, more;411 buf = malloc(8192);412 if(buf == nil)413 return nil;414 n = read(fd, buf, 8192);415 m = nil;416 if(n > 0){417 m = plumbunpackpartial(buf, n, &more);418 if(m==nil && more>0){419 /* we now know how many more bytes to read for complete message */420 buf = realloc(buf, n+more);421 if(buf == nil)422 return nil;423 if(readn(fd, buf+n, more) == more)424 m = plumbunpackpartial(buf, n+more, nil);425 }426 }427 free(buf);428 return m;429 }