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 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 int
80 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 int
94 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)
104 if(t == nil)
105 return s;
106 return strcpy(s, t) + strlen(t);
109 /* quote attribute value, if necessary */
110 static char*
111 quote(char *s)
113 char *t;
114 int c;
116 if(s == nil){
117 attrbuf[0] = '\0';
118 return attrbuf;
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;
132 *t++ = '\'';
133 *t = '\0';
134 return attrbuf;
137 char*
138 plumbpackattr(Plumbattr *attr)
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);
162 if(t > s+n)
163 abort();
164 return s;
167 char*
168 plumblookup(Plumbattr *attr, char *name)
170 while(attr){
171 if(strcmp(attr->name, name) == 0)
172 return attr->value;
173 attr = attr->next;
175 return nil;
178 char*
179 plumbpack(Plumbmsg *m, int *np)
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;
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;
215 static int
216 plumbline(char **linep, char *buf, int i, int n, int *bad)
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';
236 *linep = p;
237 i++;
239 return i;
242 void
243 plumbfree(Plumbmsg *m)
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);
257 free(m->data);
258 free(m);
261 Plumbattr*
262 plumbunpackattr(char *p)
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;
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;
306 }else{
307 if(c==' ' || c=='\t')
308 break;
309 if(c == '\''){
310 quoting = 1;
311 continue;
314 *v++ = c;
316 a->value = malloc(v-attrbuf+1);
317 if(a->value == nil){
318 free(a->name);
319 free(a);
320 break;
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 else
328 prev->next = a;
329 prev = a;
330 p = q;
332 return attr;
335 Plumbattr*
336 plumbaddattr(Plumbattr *attr, Plumbattr *new)
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;
349 Plumbattr*
350 plumbdelattr(Plumbattr *attr, char *name)
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;
360 if(l == nil)
361 return nil;
362 if(prev)
363 prev->next = l->next;
364 else
365 attr = l->next;
366 free(l->name);
367 free(l->value);
368 free(l);
369 return attr;
372 Plumbmsg*
373 plumbunpackpartial(char *buf, int n, int *morep)
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);
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';
412 if(bad){
413 plumbfree(m);
414 m = nil;
416 return m;
419 Plumbmsg*
420 plumbunpack(char *buf, int n)
422 return plumbunpackpartial(buf, n, nil);
425 Plumbmsg*
426 plumbrecv(int fd)
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);
448 free(buf);
449 return m;
452 Plumbmsg*
453 plumbrecvfid(Fid *fid)
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);
475 free(buf);
476 return m;