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 if(fsplumb == nil)17 fsplumb = nsmount("plumb", "");18 if(fsplumb == nil)19 return -1;20 /*21 * It's important that when we send something,22 * we find out whether it was a valid plumb write.23 * (If it isn't, the client might fall back to some24 * other mechanism or indicate to the user what happened.)25 * We can't use a pipe for this, so we have to use the26 * fid interface. But we need to return a fd.27 * Return a fd for /dev/null so that we return a unique28 * file descriptor. In plumbsend we'll look for pfd29 * and use the recorded fid instead.30 */31 if((omode&3) == OWRITE){32 if(pfd != -1){33 werrstr("already have plumb send open");34 return -1;35 }36 pfd = open("/dev/null", OWRITE);37 if(pfd < 0)38 return -1;39 pfid = fsopen(fsplumb, name, omode);40 if(pfid == nil){41 close(pfd);42 pfd = -1;43 return -1;44 }45 return pfd;46 }48 return fsopenfd(fsplumb, name, omode);49 }51 Fid*52 plumbopenfid(char *name, int mode)53 {54 if(fsplumb == nil)55 fsplumb = nsmount("plumb", "");56 if(fsplumb == nil)57 return nil;58 return fsopen(fsplumb, name, mode);59 }61 int62 plumbsendtofid(Fid *fid, Plumbmsg *m)63 {64 char *buf;65 int n;67 if(fid == nil){68 werrstr("invalid fid");69 return -1;70 }71 buf = plumbpack(m, &n);72 if(buf == nil)73 return -1;74 n = fswrite(fid, buf, n);75 free(buf);76 return n;77 }79 int80 plumbsend(int fd, Plumbmsg *m)81 {82 if(fd == -1){83 werrstr("invalid fd");84 return -1;85 }86 if(fd != pfd){87 werrstr("fd is not the plumber");88 return -1;89 }90 return plumbsendtofid(pfid, m);91 }93 static int94 Strlen(char *s)95 {96 if(s == nil)97 return 0;98 return strlen(s);99 }101 static char*102 Strcpy(char *s, char *t)103 {104 if(t == nil)105 return s;106 return strcpy(s, t) + strlen(t);107 }109 /* quote attribute value, if necessary */110 static char*111 quote(char *s)112 {113 char *t;114 int c;116 if(s == nil){117 attrbuf[0] = '\0';118 return attrbuf;119 }120 if(strpbrk(s, " '=\t") == nil)121 return s;122 t = attrbuf;123 *t++ = '\'';124 while(t < attrbuf+sizeof attrbuf-2){125 c = *s++;126 if(c == '\0')127 break;128 *t++ = c;129 if(c == '\'')130 *t++ = c;131 }132 *t++ = '\'';133 *t = '\0';134 return attrbuf;135 }137 char*138 plumbpackattr(Plumbattr *attr)139 {140 int n;141 Plumbattr *a;142 char *s, *t;144 if(attr == nil)145 return nil;146 n = 0;147 for(a=attr; a!=nil; a=a->next)148 n += Strlen(a->name) + 1 + Strlen(quote(a->value)) + 1;149 s = malloc(n);150 if(s == nil)151 return nil;152 t = s;153 *t = '\0';154 for(a=attr; a!=nil; a=a->next){155 if(t != s)156 *t++ = ' ';157 strcpy(t, a->name);158 strcat(t, "=");159 strcat(t, quote(a->value));160 t += strlen(t);161 }162 if(t > s+n)163 abort();164 return s;165 }167 char*168 plumblookup(Plumbattr *attr, char *name)169 {170 while(attr){171 if(strcmp(attr->name, name) == 0)172 return attr->value;173 attr = attr->next;174 }175 return nil;176 }178 char*179 plumbpack(Plumbmsg *m, int *np)180 {181 int n, ndata;182 char *buf, *p, *attr;184 ndata = m->ndata;185 if(ndata < 0)186 ndata = Strlen(m->data);187 attr = plumbpackattr(m->attr);188 n = Strlen(m->src)+1 + Strlen(m->dst)+1 + Strlen(m->wdir)+1 +189 Strlen(m->type)+1 + Strlen(attr)+1 + 16 + ndata;190 buf = malloc(n+1); /* +1 for '\0' */191 if(buf == nil){192 free(attr);193 return nil;194 }195 p = Strcpy(buf, m->src);196 *p++ = '\n';197 p = Strcpy(p, m->dst);198 *p++ = '\n';199 p = Strcpy(p, m->wdir);200 *p++ = '\n';201 p = Strcpy(p, m->type);202 *p++ = '\n';203 p = Strcpy(p, attr);204 *p++ = '\n';205 p += sprint(p, "%d\n", ndata);206 memmove(p, m->data, ndata);207 *np = (p-buf)+ndata;208 buf[*np] = '\0'; /* null terminate just in case */209 if(*np >= n+1)210 abort();211 free(attr);212 return buf;213 }215 static int216 plumbline(char **linep, char *buf, int i, int n, int *bad)217 {218 int starti;219 char *p;221 if(*bad)222 return i;223 starti = i;224 while(i<n && buf[i]!='\n')225 i++;226 if(i == n)227 *bad = 1;228 else{229 p = malloc((i-starti) + 1);230 if(p == nil)231 *bad = 1;232 else{233 memmove(p, buf+starti, i-starti);234 p[i-starti] = '\0';235 }236 *linep = p;237 i++;238 }239 return i;240 }242 void243 plumbfree(Plumbmsg *m)244 {245 Plumbattr *a, *next;247 free(m->src);248 free(m->dst);249 free(m->wdir);250 free(m->type);251 for(a=m->attr; a!=nil; a=next){252 next = a->next;253 free(a->name);254 free(a->value);255 free(a);256 }257 free(m->data);258 free(m);259 }261 Plumbattr*262 plumbunpackattr(char *p)263 {264 Plumbattr *attr, *prev, *a;265 char *q, *v;266 int c, quoting;268 attr = prev = nil;269 while(*p!='\0' && *p!='\n'){270 while(*p==' ' || *p=='\t')271 p++;272 if(*p == '\0')273 break;274 for(q=p; *q!='\0' && *q!='\n' && *q!=' ' && *q!='\t'; q++)275 if(*q == '=')276 break;277 if(*q != '=')278 break; /* malformed attribute */279 a = malloc(sizeof(Plumbattr));280 if(a == nil)281 break;282 a->name = malloc(q-p+1);283 if(a->name == nil){284 free(a);285 break;286 }287 memmove(a->name, p, q-p);288 a->name[q-p] = '\0';289 /* process quotes in value */290 q++; /* skip '=' */291 v = attrbuf;292 quoting = 0;293 while(*q!='\0' && *q!='\n'){294 if(v >= attrbuf+sizeof attrbuf)295 break;296 c = *q++;297 if(quoting){298 if(c == '\''){299 if(*q == '\'')300 q++;301 else{302 quoting = 0;303 continue;304 }305 }306 }else{307 if(c==' ' || c=='\t')308 break;309 if(c == '\''){310 quoting = 1;311 continue;312 }313 }314 *v++ = c;315 }316 a->value = malloc(v-attrbuf+1);317 if(a->value == nil){318 free(a->name);319 free(a);320 break;321 }322 memmove(a->value, attrbuf, v-attrbuf);323 a->value[v-attrbuf] = '\0';324 a->next = nil;325 if(prev == nil)326 attr = a;327 else328 prev->next = a;329 prev = a;330 p = q;331 }332 return attr;333 }335 Plumbattr*336 plumbaddattr(Plumbattr *attr, Plumbattr *new)337 {338 Plumbattr *l;340 l = attr;341 if(l == nil)342 return new;343 while(l->next != nil)344 l = l->next;345 l->next = new;346 return attr;347 }349 Plumbattr*350 plumbdelattr(Plumbattr *attr, char *name)351 {352 Plumbattr *l, *prev;354 prev = nil;355 for(l=attr; l!=nil; l=l->next){356 if(strcmp(name, l->name) == 0)357 break;358 prev = l;359 }360 if(l == nil)361 return nil;362 if(prev)363 prev->next = l->next;364 else365 attr = l->next;366 free(l->name);367 free(l->value);368 free(l);369 return attr;370 }372 Plumbmsg*373 plumbunpackpartial(char *buf, int n, int *morep)374 {375 Plumbmsg *m;376 int i, bad;377 char *ntext, *attr;379 m = malloc(sizeof(Plumbmsg));380 if(m == nil)381 return nil;382 memset(m, 0, sizeof(Plumbmsg));383 if(morep != nil)384 *morep = 0;385 bad = 0;386 i = plumbline(&m->src, buf, 0, n, &bad);387 i = plumbline(&m->dst, buf, i, n, &bad);388 i = plumbline(&m->wdir, buf, i, n, &bad);389 i = plumbline(&m->type, buf, i, n, &bad);390 i = plumbline(&attr, buf, i, n, &bad);391 m->attr = plumbunpackattr(attr);392 free(attr);393 i = plumbline(&ntext, buf, i, n, &bad);394 m->ndata = atoi(ntext);395 if(m->ndata != n-i){396 bad = 1;397 if(morep!=nil && m->ndata>n-i)398 *morep = m->ndata - (n-i);399 }400 free(ntext);401 if(!bad){402 m->data = malloc(n-i+1); /* +1 for '\0' */403 if(m->data == nil)404 bad = 1;405 else{406 memmove(m->data, buf+i, m->ndata);407 m->ndata = n-i;408 /* null-terminate in case it's text */409 m->data[m->ndata] = '\0';410 }411 }412 if(bad){413 plumbfree(m);414 m = nil;415 }416 return m;417 }419 Plumbmsg*420 plumbunpack(char *buf, int n)421 {422 return plumbunpackpartial(buf, n, nil);423 }425 Plumbmsg*426 plumbrecv(int fd)427 {428 char *buf;429 Plumbmsg *m;430 int n, more;432 buf = malloc(8192);433 if(buf == nil)434 return nil;435 n = read(fd, buf, 8192);436 m = nil;437 if(n > 0){438 m = plumbunpackpartial(buf, n, &more);439 if(m==nil && more>0){440 /* we now know how many more bytes to read for complete message */441 buf = realloc(buf, n+more);442 if(buf == nil)443 return nil;444 if(readn(fd, buf+n, more) == more)445 m = plumbunpackpartial(buf, n+more, nil);446 }447 }448 free(buf);449 return m;450 }452 Plumbmsg*453 plumbrecvfid(Fid *fid)454 {455 char *buf;456 Plumbmsg *m;457 int n, more;459 buf = malloc(8192);460 if(buf == nil)461 return nil;462 n = fsread(fid, buf, 8192);463 m = nil;464 if(n > 0){465 m = plumbunpackpartial(buf, n, &more);466 if(m==nil && more>0){467 /* we now know how many more bytes to read for complete message */468 buf = realloc(buf, n+more);469 if(buf == nil)470 return nil;471 if(fsreadn(fid, buf+n, more) == more)472 m = plumbunpackpartial(buf, n+more, nil);473 }474 }475 free(buf);476 return m;477 }