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 buf = plumbpack(m, &n);68 if(buf == nil)69 return -1;70 n = fswrite(fid, buf, n);71 free(buf);72 return n;73 }75 int76 plumbsend(int fd, Plumbmsg *m)77 {78 if(fd != pfd){79 werrstr("fd is not the plumber");80 return -1;81 }82 return plumbsendtofid(pfid, m);83 }85 static int86 Strlen(char *s)87 {88 if(s == nil)89 return 0;90 return strlen(s);91 }93 static char*94 Strcpy(char *s, char *t)95 {96 if(t == nil)97 return s;98 return strcpy(s, t) + strlen(t);99 }101 /* quote attribute value, if necessary */102 static char*103 quote(char *s)104 {105 char *t;106 int c;108 if(s == nil){109 attrbuf[0] = '\0';110 return attrbuf;111 }112 if(strpbrk(s, " '=\t") == nil)113 return s;114 t = attrbuf;115 *t++ = '\'';116 while(t < attrbuf+sizeof attrbuf-2){117 c = *s++;118 if(c == '\0')119 break;120 *t++ = c;121 if(c == '\'')122 *t++ = c;123 }124 *t++ = '\'';125 *t = '\0';126 return attrbuf;127 }129 char*130 plumbpackattr(Plumbattr *attr)131 {132 int n;133 Plumbattr *a;134 char *s, *t;136 if(attr == nil)137 return nil;138 n = 0;139 for(a=attr; a!=nil; a=a->next)140 n += Strlen(a->name) + 1 + Strlen(quote(a->value)) + 1;141 s = malloc(n);142 if(s == nil)143 return nil;144 t = s;145 *t = '\0';146 for(a=attr; a!=nil; a=a->next){147 if(t != s)148 *t++ = ' ';149 strcpy(t, a->name);150 strcat(t, "=");151 strcat(t, quote(a->value));152 t += strlen(t);153 }154 if(t > s+n)155 abort();156 return s;157 }159 char*160 plumblookup(Plumbattr *attr, char *name)161 {162 while(attr){163 if(strcmp(attr->name, name) == 0)164 return attr->value;165 attr = attr->next;166 }167 return nil;168 }170 char*171 plumbpack(Plumbmsg *m, int *np)172 {173 int n, ndata;174 char *buf, *p, *attr;176 ndata = m->ndata;177 if(ndata < 0)178 ndata = Strlen(m->data);179 attr = plumbpackattr(m->attr);180 n = Strlen(m->src)+1 + Strlen(m->dst)+1 + Strlen(m->wdir)+1 +181 Strlen(m->type)+1 + Strlen(attr)+1 + 16 + ndata;182 buf = malloc(n+1); /* +1 for '\0' */183 if(buf == nil){184 free(attr);185 return nil;186 }187 p = Strcpy(buf, m->src);188 *p++ = '\n';189 p = Strcpy(p, m->dst);190 *p++ = '\n';191 p = Strcpy(p, m->wdir);192 *p++ = '\n';193 p = Strcpy(p, m->type);194 *p++ = '\n';195 p = Strcpy(p, attr);196 *p++ = '\n';197 p += sprint(p, "%d\n", ndata);198 memmove(p, m->data, ndata);199 *np = (p-buf)+ndata;200 buf[*np] = '\0'; /* null terminate just in case */201 if(*np >= n+1)202 abort();203 free(attr);204 return buf;205 }207 static int208 plumbline(char **linep, char *buf, int i, int n, int *bad)209 {210 int starti;211 char *p;213 if(*bad)214 return i;215 starti = i;216 while(i<n && buf[i]!='\n')217 i++;218 if(i == n)219 *bad = 1;220 else{221 p = malloc((i-starti) + 1);222 if(p == nil)223 *bad = 1;224 else{225 memmove(p, buf+starti, i-starti);226 p[i-starti] = '\0';227 }228 *linep = p;229 i++;230 }231 return i;232 }234 void235 plumbfree(Plumbmsg *m)236 {237 Plumbattr *a, *next;239 free(m->src);240 free(m->dst);241 free(m->wdir);242 free(m->type);243 for(a=m->attr; a!=nil; a=next){244 next = a->next;245 free(a->name);246 free(a->value);247 free(a);248 }249 free(m->data);250 free(m);251 }253 Plumbattr*254 plumbunpackattr(char *p)255 {256 Plumbattr *attr, *prev, *a;257 char *q, *v;258 int c, quoting;260 attr = prev = nil;261 while(*p!='\0' && *p!='\n'){262 while(*p==' ' || *p=='\t')263 p++;264 if(*p == '\0')265 break;266 for(q=p; *q!='\0' && *q!='\n' && *q!=' ' && *q!='\t'; q++)267 if(*q == '=')268 break;269 if(*q != '=')270 break; /* malformed attribute */271 a = malloc(sizeof(Plumbattr));272 if(a == nil)273 break;274 a->name = malloc(q-p+1);275 if(a->name == nil){276 free(a);277 break;278 }279 memmove(a->name, p, q-p);280 a->name[q-p] = '\0';281 /* process quotes in value */282 q++; /* skip '=' */283 v = attrbuf;284 quoting = 0;285 while(*q!='\0' && *q!='\n'){286 if(v >= attrbuf+sizeof attrbuf)287 break;288 c = *q++;289 if(quoting){290 if(c == '\''){291 if(*q == '\'')292 q++;293 else{294 quoting = 0;295 continue;296 }297 }298 }else{299 if(c==' ' || c=='\t')300 break;301 if(c == '\''){302 quoting = 1;303 continue;304 }305 }306 *v++ = c;307 }308 a->value = malloc(v-attrbuf+1);309 if(a->value == nil){310 free(a->name);311 free(a);312 break;313 }314 memmove(a->value, attrbuf, v-attrbuf);315 a->value[v-attrbuf] = '\0';316 a->next = nil;317 if(prev == nil)318 attr = a;319 else320 prev->next = a;321 prev = a;322 p = q;323 }324 return attr;325 }327 Plumbattr*328 plumbaddattr(Plumbattr *attr, Plumbattr *new)329 {330 Plumbattr *l;332 l = attr;333 if(l == nil)334 return new;335 while(l->next != nil)336 l = l->next;337 l->next = new;338 return attr;339 }341 Plumbattr*342 plumbdelattr(Plumbattr *attr, char *name)343 {344 Plumbattr *l, *prev;346 prev = nil;347 for(l=attr; l!=nil; l=l->next){348 if(strcmp(name, l->name) == 0)349 break;350 prev = l;351 }352 if(l == nil)353 return nil;354 if(prev)355 prev->next = l->next;356 else357 attr = l->next;358 free(l->name);359 free(l->value);360 free(l);361 return attr;362 }364 Plumbmsg*365 plumbunpackpartial(char *buf, int n, int *morep)366 {367 Plumbmsg *m;368 int i, bad;369 char *ntext, *attr;371 m = malloc(sizeof(Plumbmsg));372 if(m == nil)373 return nil;374 memset(m, 0, sizeof(Plumbmsg));375 if(morep != nil)376 *morep = 0;377 bad = 0;378 i = plumbline(&m->src, buf, 0, n, &bad);379 i = plumbline(&m->dst, buf, i, n, &bad);380 i = plumbline(&m->wdir, buf, i, n, &bad);381 i = plumbline(&m->type, buf, i, n, &bad);382 i = plumbline(&attr, buf, i, n, &bad);383 m->attr = plumbunpackattr(attr);384 free(attr);385 i = plumbline(&ntext, buf, i, n, &bad);386 m->ndata = atoi(ntext);387 if(m->ndata != n-i){388 bad = 1;389 if(morep!=nil && m->ndata>n-i)390 *morep = m->ndata - (n-i);391 }392 free(ntext);393 if(!bad){394 m->data = malloc(n-i+1); /* +1 for '\0' */395 if(m->data == nil)396 bad = 1;397 else{398 memmove(m->data, buf+i, m->ndata);399 m->ndata = n-i;400 /* null-terminate in case it's text */401 m->data[m->ndata] = '\0';402 }403 }404 if(bad){405 plumbfree(m);406 m = nil;407 }408 return m;409 }411 Plumbmsg*412 plumbunpack(char *buf, int n)413 {414 return plumbunpackpartial(buf, n, nil);415 }417 Plumbmsg*418 plumbrecv(int fd)419 {420 char *buf;421 Plumbmsg *m;422 int n, more;424 buf = malloc(8192);425 if(buf == nil)426 return nil;427 n = read(fd, buf, 8192);428 m = nil;429 if(n > 0){430 m = plumbunpackpartial(buf, n, &more);431 if(m==nil && more>0){432 /* we now know how many more bytes to read for complete message */433 buf = realloc(buf, n+more);434 if(buf == nil)435 return nil;436 if(readn(fd, buf+n, more) == more)437 m = plumbunpackpartial(buf, n+more, nil);438 }439 }440 free(buf);441 return m;442 }444 Plumbmsg*445 plumbrecvfid(Fid *fid)446 {447 char *buf;448 Plumbmsg *m;449 int n, more;451 buf = malloc(8192);452 if(buf == nil)453 return nil;454 n = fsread(fid, buf, 8192);455 m = nil;456 if(n > 0){457 m = plumbunpackpartial(buf, n, &more);458 if(m==nil && more>0){459 /* we now know how many more bytes to read for complete message */460 buf = realloc(buf, n+more);461 if(buf == nil)462 return nil;463 if(fsreadn(fid, buf+n, more) == more)464 m = plumbunpackpartial(buf, n+more, nil);465 }466 }467 free(buf);468 return m;469 }