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