Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include "plumb.h"
4
 
5
int
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
54
Strlen(char *s)
55
{
56
	if(s == nil)
57
		return 0;
58
	return strlen(s);
59
}
60
 
61
static char*
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*
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*
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*
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*
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
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
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
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*
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*
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*
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*
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*
407
plumbunpack(char *buf, int n)
408
{
409
	return plumbunpackpartial(buf, n, nil);
410
}
411
 
412
Plumbmsg*
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
}