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 int
14 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 some
24 * other mechanism or indicate to the user what happened.)
25 * We can't use a pipe for this, so we have to use the
26 * fid interface. But we need to return a fd.
27 * Return a fd for /dev/null so that we return a unique
28 * file descriptor. In plumbsend we'll look for pfd
29 * 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 int
62 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 int
76 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 int
86 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)
105 char *t;
106 int c;
108 if(s == nil){
109 attrbuf[0] = '\0';
110 return attrbuf;
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;
124 *t++ = '\'';
125 *t = '\0';
126 return attrbuf;
129 char*
130 plumbpackattr(Plumbattr *attr)
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);
154 if(t > s+n)
155 abort();
156 return s;
159 char*
160 plumblookup(Plumbattr *attr, char *name)
162 while(attr){
163 if(strcmp(attr->name, name) == 0)
164 return attr->value;
165 attr = attr->next;
167 return nil;
170 char*
171 plumbpack(Plumbmsg *m, int *np)
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;
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;
207 static int
208 plumbline(char **linep, char *buf, int i, int n, int *bad)
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';
228 *linep = p;
229 i++;
231 return i;
234 void
235 plumbfree(Plumbmsg *m)
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);
249 free(m->data);
250 free(m);
253 Plumbattr*
254 plumbunpackattr(char *p)
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;
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;
298 }else{
299 if(c==' ' || c=='\t')
300 break;
301 if(c == '\''){
302 quoting = 1;
303 continue;
306 *v++ = c;
308 a->value = malloc(v-attrbuf+1);
309 if(a->value == nil){
310 free(a->name);
311 free(a);
312 break;
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 else
320 prev->next = a;
321 prev = a;
322 p = q;
324 return attr;
327 Plumbattr*
328 plumbaddattr(Plumbattr *attr, Plumbattr *new)
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;
341 Plumbattr*
342 plumbdelattr(Plumbattr *attr, char *name)
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;
352 if(l == nil)
353 return nil;
354 if(prev)
355 prev->next = l->next;
356 else
357 attr = l->next;
358 free(l->name);
359 free(l->value);
360 free(l);
361 return attr;
364 Plumbmsg*
365 plumbunpackpartial(char *buf, int n, int *morep)
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);
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';
404 if(bad){
405 plumbfree(m);
406 m = nil;
408 return m;
411 Plumbmsg*
412 plumbunpack(char *buf, int n)
414 return plumbunpackpartial(buf, n, nil);
417 Plumbmsg*
418 plumbrecv(int fd)
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);
440 free(buf);
441 return m;
444 Plumbmsg*
445 plumbrecvfid(Fid *fid)
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);
467 free(buf);
468 return m;