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