1 #include <u.h>
2 #include <libc.h>
3 #include "plumb.h"
4
5 int
plumbopen(char * name,int omode)6 plumbopen(char *name, int omode)
7 {
8 int fd, f;
9 char *s, *plumber;
10 char buf[128], err[ERRMAX];
11
12 if(name[0] == '/')
13 return open(name, omode);
14
15 /* find elusive plumber */
16 if(access("/mnt/plumb/send", AWRITE) >= 0)
17 plumber = "/mnt/plumb";
18 else if(access("/mnt/term/mnt/plumb/send", AWRITE) >= 0)
19 plumber = "/mnt/term/mnt/plumb";
20 else{
21 /* last resort: try mounting service */
22 plumber = "/mnt/plumb";
23 s = getenv("plumbsrv");
24 if(s == nil)
25 return -1;
26 f = open(s, ORDWR);
27 free(s);
28 if(f < 0)
29 return -1;
30 if(mount(f, -1, "/mnt/plumb", MREPL, "") < 0){
31 close(f);
32 return -1;
33 }
34 if(access("/mnt/plumb/send", AWRITE) < 0)
35 return -1;
36 }
37
38 snprint(buf, sizeof buf, "%s/%s", plumber, name);
39 fd = open(buf, omode);
40 if(fd >= 0)
41 return fd;
42
43 /* try creating port; used by non-standard plumb implementations */
44 rerrstr(err, sizeof err);
45 fd = create(buf, omode, 0600);
46 if(fd >= 0)
47 return fd;
48 errstr(err, sizeof err);
49
50 return -1;
51 }
52
53 static int
Strlen(char * s)54 Strlen(char *s)
55 {
56 if(s == nil)
57 return 0;
58 return strlen(s);
59 }
60
61 static char*
Strcpy(char * s,char * t)62 Strcpy(char *s, char *t)
63 {
64 if(t == nil)
65 return s;
66 return strcpy(s, t) + strlen(t);
67 }
68
69 /* quote attribute value, if necessary */
70 static char*
quote(char * s,char * buf,char * bufe)71 quote(char *s, char *buf, char *bufe)
72 {
73 char *t;
74 int c;
75
76 if(s == nil){
77 buf[0] = '\0';
78 return buf;
79 }
80 if(strpbrk(s, " '=\t") == nil)
81 return s;
82 t = buf;
83 *t++ = '\'';
84 while(t < bufe-2){
85 c = *s++;
86 if(c == '\0')
87 break;
88 *t++ = c;
89 if(c == '\'')
90 *t++ = c;
91 }
92 *t++ = '\'';
93 *t = '\0';
94 return buf;
95 }
96
97 char*
plumbpackattr(Plumbattr * attr)98 plumbpackattr(Plumbattr *attr)
99 {
100 int n;
101 Plumbattr *a;
102 char *s, *t, *buf, *bufe;
103
104 if(attr == nil)
105 return nil;
106 if((buf = malloc(4096)) == nil)
107 return nil;
108 bufe = buf + 4096;
109 n = 0;
110 for(a=attr; a!=nil; a=a->next)
111 n += Strlen(a->name) + 1 + Strlen(quote(a->value, buf, bufe)) + 1;
112 s = malloc(n);
113 if(s == nil) {
114 free(buf);
115 return nil;
116 }
117 t = s;
118 *t = '\0';
119 for(a=attr; a!=nil; a=a->next){
120 if(t != s)
121 *t++ = ' ';
122 strcpy(t, a->name);
123 strcat(t, "=");
124 strcat(t, quote(a->value, buf, bufe));
125 t += strlen(t);
126 }
127 if(t > s+n)
128 abort();
129 free(buf);
130 return s;
131 }
132
133 char*
plumblookup(Plumbattr * attr,char * name)134 plumblookup(Plumbattr *attr, char *name)
135 {
136 while(attr){
137 if(strcmp(attr->name, name) == 0)
138 return attr->value;
139 attr = attr->next;
140 }
141 return nil;
142 }
143
144 char*
plumbpack(Plumbmsg * m,int * np)145 plumbpack(Plumbmsg *m, int *np)
146 {
147 int n, ndata;
148 char *buf, *p, *attr;
149
150 ndata = m->ndata;
151 if(ndata < 0)
152 ndata = Strlen(m->data);
153 attr = plumbpackattr(m->attr);
154 n = Strlen(m->src)+1 + Strlen(m->dst)+1 + Strlen(m->wdir)+1 +
155 Strlen(m->type)+1 + Strlen(attr)+1 + 16 + ndata;
156 buf = malloc(n+1); /* +1 for '\0' */
157 if(buf == nil){
158 free(attr);
159 return nil;
160 }
161 p = Strcpy(buf, m->src);
162 *p++ = '\n';
163 p = Strcpy(p, m->dst);
164 *p++ = '\n';
165 p = Strcpy(p, m->wdir);
166 *p++ = '\n';
167 p = Strcpy(p, m->type);
168 *p++ = '\n';
169 p = Strcpy(p, attr);
170 *p++ = '\n';
171 p += sprint(p, "%d\n", ndata);
172 memmove(p, m->data, ndata);
173 *np = (p-buf)+ndata;
174 buf[*np] = '\0'; /* null terminate just in case */
175 if(*np >= n+1)
176 abort();
177 free(attr);
178 return buf;
179 }
180
181 int
plumbsend(int fd,Plumbmsg * m)182 plumbsend(int fd, Plumbmsg *m)
183 {
184 char *buf;
185 int n;
186
187 buf = plumbpack(m, &n);
188 if(buf == nil)
189 return -1;
190 n = write(fd, buf, n);
191 free(buf);
192 return n;
193 }
194
195 static int
plumbline(char ** linep,char * buf,int i,int n,int * bad)196 plumbline(char **linep, char *buf, int i, int n, int *bad)
197 {
198 int starti;
199 char *p;
200
201 starti = i;
202 while(i<n && buf[i]!='\n')
203 i++;
204 if(i == n)
205 *bad = 1;
206 else{
207 p = malloc((i-starti) + 1);
208 if(p == nil)
209 *bad = 1;
210 else{
211 memmove(p, buf+starti, i-starti);
212 p[i-starti] = '\0';
213 }
214 *linep = p;
215 i++;
216 }
217 return i;
218 }
219
220 void
plumbfree(Plumbmsg * m)221 plumbfree(Plumbmsg *m)
222 {
223 Plumbattr *a, *next;
224
225 free(m->src);
226 free(m->dst);
227 free(m->wdir);
228 free(m->type);
229 for(a=m->attr; a!=nil; a=next){
230 next = a->next;
231 free(a->name);
232 free(a->value);
233 free(a);
234 }
235 free(m->data);
236 free(m);
237 }
238
239 Plumbattr*
plumbunpackattr(char * p)240 plumbunpackattr(char *p)
241 {
242 Plumbattr *attr, *prev, *a;
243 char *q, *v, *buf, *bufe;
244 int c, quoting;
245
246 buf = malloc(4096);
247 if(buf == nil)
248 return nil;
249 bufe = buf + 4096;
250 attr = prev = nil;
251 while(*p!='\0' && *p!='\n'){
252 while(*p==' ' || *p=='\t')
253 p++;
254 if(*p == '\0')
255 break;
256 for(q=p; *q!='\0' && *q!='\n' && *q!=' ' && *q!='\t'; q++)
257 if(*q == '=')
258 break;
259 if(*q != '=')
260 break; /* malformed attribute */
261 a = malloc(sizeof(Plumbattr));
262 if(a == nil)
263 break;
264 a->name = malloc(q-p+1);
265 if(a->name == nil){
266 free(a);
267 break;
268 }
269 memmove(a->name, p, q-p);
270 a->name[q-p] = '\0';
271 /* process quotes in value */
272 q++; /* skip '=' */
273 v = buf;
274 quoting = 0;
275 while(*q!='\0' && *q!='\n'){
276 if(v >= bufe)
277 break;
278 c = *q++;
279 if(quoting){
280 if(c == '\''){
281 if(*q == '\'')
282 q++;
283 else{
284 quoting = 0;
285 continue;
286 }
287 }
288 }else{
289 if(c==' ' || c=='\t')
290 break;
291 if(c == '\''){
292 quoting = 1;
293 continue;
294 }
295 }
296 *v++ = c;
297 }
298 a->value = malloc(v-buf+1);
299 if(a->value == nil){
300 free(a->name);
301 free(a);
302 break;
303 }
304 memmove(a->value, buf, v-buf);
305 a->value[v-buf] = '\0';
306 a->next = nil;
307 if(prev == nil)
308 attr = a;
309 else
310 prev->next = a;
311 prev = a;
312 p = q;
313 }
314 free(buf);
315 return attr;
316 }
317
318 Plumbattr*
plumbaddattr(Plumbattr * attr,Plumbattr * new)319 plumbaddattr(Plumbattr *attr, Plumbattr *new)
320 {
321 Plumbattr *l;
322
323 l = attr;
324 if(l == nil)
325 return new;
326 while(l->next != nil)
327 l = l->next;
328 l->next = new;
329 return attr;
330 }
331
332 Plumbattr*
plumbdelattr(Plumbattr * attr,char * name)333 plumbdelattr(Plumbattr *attr, char *name)
334 {
335 Plumbattr *l, *prev;
336
337 prev = nil;
338 for(l=attr; l!=nil; l=l->next){
339 if(strcmp(name, l->name) == 0)
340 break;
341 prev = l;
342 }
343 if(l == nil)
344 return nil;
345 if(prev)
346 prev->next = l->next;
347 else
348 attr = l->next;
349 free(l->name);
350 free(l->value);
351 free(l);
352 return attr;
353 }
354
355 Plumbmsg*
plumbunpackpartial(char * buf,int n,int * morep)356 plumbunpackpartial(char *buf, int n, int *morep)
357 {
358 Plumbmsg *m;
359 int i, bad;
360 char *ntext, *attr;
361
362 m = malloc(sizeof(Plumbmsg));
363 if(m == nil)
364 return nil;
365 memset(m, 0, sizeof(Plumbmsg));
366 if(morep != nil)
367 *morep = 0;
368 bad = 0;
369 i = plumbline(&m->src, buf, 0, n, &bad);
370 i = plumbline(&m->dst, buf, i, n, &bad);
371 i = plumbline(&m->wdir, buf, i, n, &bad);
372 i = plumbline(&m->type, buf, i, n, &bad);
373 i = plumbline(&attr, buf, i, n, &bad);
374 i = plumbline(&ntext, buf, i, n, &bad);
375 if(bad){
376 plumbfree(m);
377 return nil;
378 }
379 m->attr = plumbunpackattr(attr);
380 free(attr);
381 m->ndata = atoi(ntext);
382 if(m->ndata != n-i){
383 bad = 1;
384 if(morep!=nil && m->ndata>n-i)
385 *morep = m->ndata - (n-i);
386 }
387 free(ntext);
388 if(!bad){
389 m->data = malloc(n-i+1); /* +1 for '\0' */
390 if(m->data == nil)
391 bad = 1;
392 else{
393 memmove(m->data, buf+i, m->ndata);
394 m->ndata = n-i;
395 /* null-terminate in case it's text */
396 m->data[m->ndata] = '\0';
397 }
398 }
399 if(bad){
400 plumbfree(m);
401 m = nil;
402 }
403 return m;
404 }
405
406 Plumbmsg*
plumbunpack(char * buf,int n)407 plumbunpack(char *buf, int n)
408 {
409 return plumbunpackpartial(buf, n, nil);
410 }
411
412 Plumbmsg*
plumbrecv(int fd)413 plumbrecv(int fd)
414 {
415 char *buf;
416 Plumbmsg *m;
417 int n, more;
418
419 buf = malloc(8192);
420 if(buf == nil)
421 return nil;
422 n = read(fd, buf, 8192);
423 m = nil;
424 if(n > 0){
425 m = plumbunpackpartial(buf, n, &more);
426 if(m==nil && more>0){
427 /* we now know how many more bytes to read for complete message */
428 buf = realloc(buf, n+more);
429 if(buf == nil)
430 return nil;
431 if(readn(fd, buf+n, more) == more)
432 m = plumbunpackpartial(buf, n+more, nil);
433 }
434 }
435 free(buf);
436 return m;
437 }
438