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 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 some
26 * other mechanism or indicate to the user what happened.)
27 * We can't use a pipe for this, so we have to use the
28 * fid interface. But we need to return a fd.
29 * Return a fd for /dev/null so that we return a unique
30 * file descriptor. In plumbsend we'll look for pfd
31 * 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 int
55 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 int
73 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;
111 *t++ = '\'';
112 *t = '\0';
113 return attrbuf;
116 char*
117 plumbpackattr(Plumbattr *attr)
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);
141 if(t > s+n)
142 abort();
143 return s;
146 char*
147 plumblookup(Plumbattr *attr, char *name)
149 while(attr){
150 if(strcmp(attr->name, name) == 0)
151 return attr->value;
152 attr = attr->next;
154 return nil;
157 char*
158 plumbpack(Plumbmsg *m, int *np)
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;
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;
194 static int
195 plumbline(char **linep, char *buf, int i, int n, int *bad)
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';
215 *linep = p;
216 i++;
218 return i;
221 void
222 plumbfree(Plumbmsg *m)
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);
236 free(m->data);
237 free(m);
240 Plumbattr*
241 plumbunpackattr(char *p)
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;
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;
285 }else{
286 if(c==' ' || c=='\t')
287 break;
288 if(c == '\''){
289 quoting = 1;
290 continue;
293 *v++ = c;
295 a->value = malloc(v-attrbuf+1);
296 if(a->value == nil){
297 free(a->name);
298 free(a);
299 break;
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 else
307 prev->next = a;
308 prev = a;
309 p = q;
311 return attr;
314 Plumbattr*
315 plumbaddattr(Plumbattr *attr, Plumbattr *new)
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;
328 Plumbattr*
329 plumbdelattr(Plumbattr *attr, char *name)
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;
339 if(l == nil)
340 return nil;
341 if(prev)
342 prev->next = l->next;
343 else
344 attr = l->next;
345 free(l->name);
346 free(l->value);
347 free(l);
348 return attr;
351 Plumbmsg*
352 plumbunpackpartial(char *buf, int n, int *morep)
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);
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';
391 if(bad){
392 plumbfree(m);
393 m = nil;
395 return m;
398 Plumbmsg*
399 plumbunpack(char *buf, int n)
401 return plumbunpackpartial(buf, n, nil);
404 Plumbmsg*
405 plumbrecv(int fd)
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);
427 free(buf);
428 return m;