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 } 438