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