xref: /plan9/sys/src/libplumb/mesg.c (revision 9b7bf7df4595c26f1e9b67beb0c6e44c9876fb05)
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