1 #include "inc.h" 2 #include "store.h" 3 4 /* Allocate space for the data store. */ 5 static struct data_store ds_store[NR_DS_KEYS]; 6 static struct subscription ds_subs[NR_DS_SUBS]; 7 8 /*===========================================================================* 9 * alloc_data_slot * 10 *===========================================================================*/ 11 static struct data_store *alloc_data_slot(void) 12 { 13 /* Allocate a new data slot. */ 14 int i; 15 16 for (i = 0; i < NR_DS_KEYS; i++) { 17 if (!(ds_store[i].flags & DSF_IN_USE)) 18 return &ds_store[i]; 19 } 20 21 return NULL; 22 } 23 24 /*===========================================================================* 25 * alloc_sub_slot * 26 *===========================================================================*/ 27 static struct subscription *alloc_sub_slot(void) 28 { 29 /* Return a free subscription slot. */ 30 int i; 31 32 for (i = 0; i < NR_DS_SUBS; i++) { 33 if (!(ds_subs[i].flags & DSF_IN_USE)) 34 return &ds_subs[i]; 35 } 36 37 return NULL; 38 } 39 40 /*===========================================================================* 41 * free_sub_slot * 42 *===========================================================================*/ 43 static void free_sub_slot(struct subscription *subp) 44 { 45 /* Clean up a previously successfully) allocated subscription slot. */ 46 assert(subp->flags & DSF_IN_USE); 47 48 regfree(&subp->regex); 49 memset(&subp->regex, 0, sizeof(subp->regex)); 50 51 subp->flags = 0; 52 } 53 54 /*===========================================================================* 55 * lookup_entry * 56 *===========================================================================*/ 57 static struct data_store *lookup_entry(const char *key_name, int type) 58 { 59 /* Lookup an existing entry by key and type. */ 60 int i; 61 62 for (i = 0; i < NR_DS_KEYS; i++) { 63 if ((ds_store[i].flags & DSF_IN_USE) /* used */ 64 && (ds_store[i].flags & type) /* same type*/ 65 && !strcmp(ds_store[i].key, key_name)) /* same key*/ 66 return &ds_store[i]; 67 } 68 69 return NULL; 70 } 71 72 /*===========================================================================* 73 * lookup_label_entry * 74 *===========================================================================*/ 75 static struct data_store *lookup_label_entry(unsigned num) 76 { 77 /* Lookup an existing label entry by num. */ 78 int i; 79 80 for (i = 0; i < NR_DS_KEYS; i++) { 81 if ((ds_store[i].flags & DSF_IN_USE) 82 && (ds_store[i].flags & DSF_TYPE_LABEL) 83 && (ds_store[i].u.u32 == num)) 84 return &ds_store[i]; 85 } 86 87 return NULL; 88 } 89 90 /*===========================================================================* 91 * lookup_sub * 92 *===========================================================================*/ 93 static struct subscription *lookup_sub(const char *owner) 94 { 95 /* Lookup an existing subscription given its owner. */ 96 int i; 97 98 for (i = 0; i < NR_DS_SUBS; i++) { 99 if ((ds_subs[i].flags & DSF_IN_USE) /* used */ 100 && !strcmp(ds_subs[i].owner, owner)) /* same key*/ 101 return &ds_subs[i]; 102 } 103 104 return NULL; 105 } 106 107 /*===========================================================================* 108 * ds_getprocname * 109 *===========================================================================*/ 110 static char *ds_getprocname(endpoint_t e) 111 { 112 /* Get a process name given its endpoint. */ 113 struct data_store *dsp; 114 115 static char *first_proc_name = "ds"; 116 endpoint_t first_proc_ep = DS_PROC_NR; 117 118 if(e == first_proc_ep) 119 return first_proc_name; 120 121 if((dsp = lookup_label_entry(e)) != NULL) 122 return dsp->key; 123 124 return NULL; 125 } 126 127 /*===========================================================================* 128 * ds_getprocep * 129 *===========================================================================*/ 130 static endpoint_t ds_getprocep(const char *s) 131 { 132 /* Get a process endpoint given its name. */ 133 struct data_store *dsp; 134 135 if((dsp = lookup_entry(s, DSF_TYPE_LABEL)) != NULL) 136 return dsp->u.u32; 137 panic("ds_getprocep: process endpoint not found"); 138 } 139 140 /*===========================================================================* 141 * check_auth * 142 *===========================================================================*/ 143 static int check_auth(const struct data_store *p, endpoint_t ep, int perm) 144 { 145 /* Check authorization for a given type of permission. */ 146 char *source; 147 148 if(!(p->flags & perm)) 149 return 1; 150 151 source = ds_getprocname(ep); 152 return source && !strcmp(p->owner, source); 153 } 154 155 /*===========================================================================* 156 * get_key_name * 157 *===========================================================================*/ 158 static int get_key_name(const message *m_ptr, char *key_name) 159 { 160 /* Get key name given an input message. */ 161 int r; 162 163 if (m_ptr->m_ds_req.key_len > DS_MAX_KEYLEN || m_ptr->m_ds_req.key_len < 2) { 164 printf("DS: bogus key length (%d) from %d\n", m_ptr->m_ds_req.key_len, 165 m_ptr->m_source); 166 return EINVAL; 167 } 168 169 /* Copy name from caller. */ 170 r = sys_safecopyfrom(m_ptr->m_source, 171 (cp_grant_id_t) m_ptr->m_ds_req.key_grant, 0, 172 (vir_bytes) key_name, m_ptr->m_ds_req.key_len); 173 if(r != OK) { 174 printf("DS: publish: copy failed from %d: %d\n", m_ptr->m_source, r); 175 return r; 176 } 177 178 key_name[DS_MAX_KEYLEN-1] = '\0'; 179 180 return OK; 181 } 182 183 /*===========================================================================* 184 * check_sub_match * 185 *===========================================================================*/ 186 static int check_sub_match(const struct subscription *subp, 187 struct data_store *dsp, endpoint_t ep) 188 { 189 /* Check if an entry matches a subscription. Return 1 in case of match. */ 190 return (check_auth(dsp, ep, DSF_PRIV_SUBSCRIBE) 191 && regexec(&subp->regex, dsp->key, 0, NULL, 0) == 0) 192 ? 1 : 0; 193 } 194 195 /*===========================================================================* 196 * update_subscribers * 197 *===========================================================================*/ 198 static void update_subscribers(struct data_store *dsp, int set) 199 { 200 /* If set = 1, set bit in the sub bitmap of any subscription matching the given 201 * entry, otherwise clear it. In both cases, notify the subscriber. 202 */ 203 int i; 204 int nr = dsp - ds_store; 205 endpoint_t ep; 206 207 for(i = 0; i < NR_DS_SUBS; i++) { 208 if(!(ds_subs[i].flags & DSF_IN_USE)) 209 continue; 210 if(!(ds_subs[i].flags & dsp->flags & DSF_MASK_TYPE)) 211 continue; 212 213 ep = ds_getprocep(ds_subs[i].owner); 214 if(!check_sub_match(&ds_subs[i], dsp, ep)) 215 continue; 216 217 if(set == 1) { 218 SET_BIT(ds_subs[i].old_subs, nr); 219 } else { 220 UNSET_BIT(ds_subs[i].old_subs, nr); 221 } 222 ipc_notify(ep); 223 } 224 } 225 226 /*===========================================================================* 227 * map_service * 228 *===========================================================================*/ 229 static int map_service(const struct rprocpub *rpub) 230 { 231 /* Map a new service by registering its label. */ 232 struct data_store *dsp; 233 234 /* Allocate a new data slot. */ 235 if((dsp = alloc_data_slot()) == NULL) { 236 return ENOMEM; 237 } 238 239 /* Set attributes. */ 240 strcpy(dsp->key, rpub->label); 241 dsp->u.u32 = (u32_t) rpub->endpoint; 242 strcpy(dsp->owner, "rs"); 243 dsp->flags = DSF_IN_USE | DSF_TYPE_LABEL; 244 245 /* Update subscribers having a matching subscription. */ 246 update_subscribers(dsp, 1); 247 248 return(OK); 249 } 250 251 /*===========================================================================* 252 * sef_cb_init_fresh * 253 *===========================================================================*/ 254 int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *info) 255 { 256 /* Initialize the data store server. */ 257 int i, r; 258 struct rprocpub rprocpub[NR_BOOT_PROCS]; 259 260 /* Reset data store: data and subscriptions. */ 261 for(i = 0; i < NR_DS_KEYS; i++) { 262 ds_store[i].flags = 0; 263 } 264 for(i = 0; i < NR_DS_SUBS; i++) { 265 ds_subs[i].flags = 0; 266 } 267 268 /* Map all the services in the boot image. */ 269 if((r = sys_safecopyfrom(RS_PROC_NR, info->rproctab_gid, 0, 270 (vir_bytes) rprocpub, sizeof(rprocpub))) != OK) { 271 panic("sys_safecopyfrom failed: %d", r); 272 } 273 for(i=0;i < NR_BOOT_PROCS;i++) { 274 if(rprocpub[i].in_use) { 275 if((r = map_service(&rprocpub[i])) != OK) { 276 panic("unable to map service: %d", r); 277 } 278 } 279 } 280 281 return(OK); 282 } 283 284 /*===========================================================================* 285 * do_publish * 286 *===========================================================================*/ 287 int do_publish(message *m_ptr) 288 { 289 struct data_store *dsp; 290 char key_name[DS_MAX_KEYLEN]; 291 char *source; 292 int flags = m_ptr->m_ds_req.flags; 293 size_t length; 294 int r; 295 296 /* Lookup the source. */ 297 source = ds_getprocname(m_ptr->m_source); 298 if(source == NULL) 299 return EPERM; 300 301 /* Only RS can publish labels. */ 302 if((flags & DSF_TYPE_LABEL) && m_ptr->m_source != RS_PROC_NR) 303 return EPERM; 304 305 /* Get key name. */ 306 if((r = get_key_name(m_ptr, key_name)) != OK) 307 return r; 308 309 /* Lookup the entry. */ 310 dsp = lookup_entry(key_name, flags & DSF_MASK_TYPE); 311 /* If type is LABEL, also try to lookup the entry by num. */ 312 if((flags & DSF_TYPE_LABEL) && (dsp == NULL)) 313 dsp = lookup_label_entry(m_ptr->m_ds_req.val_in.ep); 314 315 if(dsp == NULL) { 316 /* The entry doesn't exist, allocate a new data slot. */ 317 if((dsp = alloc_data_slot()) == NULL) 318 return ENOMEM; 319 } else if (flags & DSF_OVERWRITE) { 320 /* Overwrite. */ 321 if(!check_auth(dsp, m_ptr->m_source, DSF_PRIV_OVERWRITE)) 322 return EPERM; 323 } else { 324 /* Don't overwrite and return error. */ 325 return EEXIST; 326 } 327 328 /* Store! */ 329 switch(flags & DSF_MASK_TYPE) { 330 case DSF_TYPE_U32: 331 dsp->u.u32 = m_ptr->m_ds_req.val_in.u32; 332 break; 333 case DSF_TYPE_LABEL: 334 dsp->u.u32 = m_ptr->m_ds_req.val_in.ep; 335 break; 336 case DSF_TYPE_STR: 337 case DSF_TYPE_MEM: 338 length = m_ptr->m_ds_req.val_len; 339 /* Allocate a new data buffer if necessary. */ 340 if(!(dsp->flags & DSF_IN_USE)) { 341 if((dsp->u.mem.data = malloc(length)) == NULL) 342 return ENOMEM; 343 dsp->u.mem.reallen = length; 344 } else if(length > dsp->u.mem.reallen) { 345 free(dsp->u.mem.data); 346 if((dsp->u.mem.data = malloc(length)) == NULL) 347 return ENOMEM; 348 dsp->u.mem.reallen = length; 349 } 350 351 /* Copy the memory range. */ 352 r = sys_safecopyfrom(m_ptr->m_source, m_ptr->m_ds_req.val_in.grant, 353 0, (vir_bytes) dsp->u.mem.data, length); 354 if(r != OK) { 355 printf("DS: publish: memory map/copy failed from %d: %d\n", 356 m_ptr->m_source, r); 357 free(dsp->u.mem.data); 358 return r; 359 } 360 dsp->u.mem.length = length; 361 if(flags & DSF_TYPE_STR) { 362 ((char*)dsp->u.mem.data)[length-1] = '\0'; 363 } 364 break; 365 default: 366 return EINVAL; 367 } 368 369 /* Set attributes. */ 370 strcpy(dsp->key, key_name); 371 strcpy(dsp->owner, source); 372 dsp->flags = DSF_IN_USE | (flags & DSF_MASK_INTERNAL); 373 374 /* Update subscribers having a matching subscription. */ 375 update_subscribers(dsp, 1); 376 377 return(OK); 378 } 379 380 /*===========================================================================* 381 * do_retrieve * 382 *===========================================================================*/ 383 int do_retrieve(message *m_ptr) 384 { 385 struct data_store *dsp; 386 char key_name[DS_MAX_KEYLEN]; 387 int flags = m_ptr->m_ds_req.flags; 388 int type = flags & DSF_MASK_TYPE; 389 size_t length; 390 int r; 391 392 /* Get key name. */ 393 if((r = get_key_name(m_ptr, key_name)) != OK) 394 return r; 395 396 /* Lookup the entry. */ 397 if((dsp = lookup_entry(key_name, type)) == NULL) 398 return ESRCH; 399 if(!check_auth(dsp, m_ptr->m_source, DSF_PRIV_RETRIEVE)) 400 return EPERM; 401 402 /* Copy the requested data. */ 403 switch(type) { 404 case DSF_TYPE_U32: 405 m_ptr->m_ds_reply.val_out.u32 = dsp->u.u32; 406 break; 407 case DSF_TYPE_LABEL: 408 m_ptr->m_ds_reply.val_out.ep = dsp->u.u32; 409 break; 410 case DSF_TYPE_STR: 411 case DSF_TYPE_MEM: 412 length = MIN(m_ptr->m_ds_req.val_len, dsp->u.mem.length); 413 r = sys_safecopyto(m_ptr->m_source, m_ptr->m_ds_req.val_in.grant, 0, 414 (vir_bytes) dsp->u.mem.data, length); 415 if(r != OK) { 416 printf("DS: retrieve: copy failed to %d: %d\n", 417 m_ptr->m_source, r); 418 return r; 419 } 420 m_ptr->m_ds_reply.val_len = length; 421 break; 422 default: 423 return EINVAL; 424 } 425 426 return OK; 427 } 428 429 /*===========================================================================* 430 * do_retrieve_label * 431 *===========================================================================*/ 432 int do_retrieve_label(const message *m_ptr) 433 { 434 struct data_store *dsp; 435 int r; 436 437 /* Lookup the label entry. */ 438 if((dsp = lookup_label_entry(m_ptr->m_ds_req.val_in.ep)) == NULL) 439 return ESRCH; 440 441 /* Copy the key name. */ 442 r = sys_safecopyto(m_ptr->m_source, 443 (cp_grant_id_t) m_ptr->m_ds_req.key_grant, (vir_bytes) 0, 444 (vir_bytes) dsp->key, strlen(dsp->key) + 1); 445 if(r != OK) { 446 printf("DS: copy failed from %d: %d\n", m_ptr->m_source, r); 447 return r; 448 } 449 450 return OK; 451 } 452 453 /*===========================================================================* 454 * do_subscribe * 455 *===========================================================================*/ 456 int do_subscribe(message *m_ptr) 457 { 458 char regex[DS_MAX_KEYLEN+2]; 459 struct subscription *subp; 460 char errbuf[80]; 461 char *owner; 462 int type_set; 463 int r, e, b; 464 465 /* Find the owner. */ 466 owner = ds_getprocname(m_ptr->m_source); 467 if(owner == NULL) 468 return ESRCH; 469 470 /* See if the owner already has an existing subscription. */ 471 if ((subp = lookup_sub(owner)) != NULL) { 472 /* If a subscription exists but we can't overwrite, return error. */ 473 if (!(m_ptr->m_ds_req.flags & DSF_OVERWRITE)) 474 return EEXIST; 475 /* Otherwise just free the old one. */ 476 free_sub_slot(subp); 477 } 478 479 /* Find a free subscription slot. */ 480 if ((subp = alloc_sub_slot()) == NULL) 481 return EAGAIN; 482 483 /* Copy key name from the caller. Anchor the subscription with "^regexp$" so 484 * substrings don't match. The caller will probably not expect this, 485 * and the usual case is for a complete match. 486 */ 487 regex[0] = '^'; 488 if((r = get_key_name(m_ptr, regex+1)) != OK) 489 return r; 490 strcat(regex, "$"); 491 492 /* Compile regular expression. */ 493 if((e=regcomp(&subp->regex, regex, REG_EXTENDED)) != 0) { 494 regerror(e, &subp->regex, errbuf, sizeof(errbuf)); 495 printf("DS: subscribe: regerror: %s\n", errbuf); 496 memset(&subp->regex, 0, sizeof(subp->regex)); 497 return EINVAL; 498 } 499 500 /* If type_set = 0, then subscribe all types. */ 501 type_set = m_ptr->m_ds_req.flags & DSF_MASK_TYPE; 502 if(type_set == 0) 503 type_set = DSF_MASK_TYPE; 504 505 subp->flags = DSF_IN_USE | type_set; 506 strcpy(subp->owner, owner); 507 for(b = 0; b < BITMAP_CHUNKS(NR_DS_KEYS); b++) 508 subp->old_subs[b] = 0; 509 510 /* See if caller requested an instant initial list. */ 511 if(m_ptr->m_ds_req.flags & DSF_INITIAL) { 512 int i, match_found = FALSE; 513 for(i = 0; i < NR_DS_KEYS; i++) { 514 if(!(ds_store[i].flags & DSF_IN_USE)) 515 continue; 516 if(!(ds_store[i].flags & type_set)) 517 continue; 518 if(!check_sub_match(subp, &ds_store[i], m_ptr->m_source)) 519 continue; 520 521 SET_BIT(subp->old_subs, i); 522 match_found = TRUE; 523 } 524 525 /* Notify in case of match. */ 526 if(match_found) 527 ipc_notify(m_ptr->m_source); 528 } 529 530 return OK; 531 } 532 533 /*===========================================================================* 534 * do_check * 535 *===========================================================================*/ 536 int do_check(message *m_ptr) 537 { 538 struct subscription *subp; 539 char *owner; 540 endpoint_t entry_owner_e; 541 int r, i; 542 543 /* Find the subscription owner. */ 544 owner = ds_getprocname(m_ptr->m_source); 545 if(owner == NULL) 546 return ESRCH; 547 548 /* Lookup the owner's subscription. */ 549 if((subp = lookup_sub(owner)) == NULL) 550 return ESRCH; 551 552 /* Look for an updated entry the subscriber is interested in. */ 553 for(i = 0; i < NR_DS_KEYS; i++) { 554 if(GET_BIT(subp->old_subs, i)) 555 break; 556 } 557 if(i == NR_DS_KEYS) 558 return ENOENT; 559 560 /* Copy the key name. */ 561 r = sys_safecopyto(m_ptr->m_source, 562 (cp_grant_id_t) m_ptr->m_ds_req.key_grant, (vir_bytes) 0, 563 (vir_bytes) ds_store[i].key, strlen(ds_store[i].key) + 1); 564 if(r != OK) { 565 printf("DS: check: copy failed from %d: %d\n", m_ptr->m_source, r); 566 return r; 567 } 568 569 /* Copy the type and the owner of the original entry. */ 570 entry_owner_e = ds_getprocep(ds_store[i].owner); 571 m_ptr->m_ds_req.flags = ds_store[i].flags & DSF_MASK_TYPE; 572 m_ptr->m_ds_req.owner = entry_owner_e; 573 574 /* Mark the entry as no longer updated for the subscriber. */ 575 UNSET_BIT(subp->old_subs, i); 576 577 return OK; 578 } 579 580 /*===========================================================================* 581 * do_delete * 582 *===========================================================================*/ 583 int do_delete(message *m_ptr) 584 { 585 struct data_store *dsp; 586 char key_name[DS_MAX_KEYLEN]; 587 char *source; 588 char *label; 589 int type = m_ptr->m_ds_req.flags & DSF_MASK_TYPE; 590 int i, r; 591 592 /* Lookup the source. */ 593 source = ds_getprocname(m_ptr->m_source); 594 if(source == NULL) 595 return EPERM; 596 597 /* Get key name. */ 598 if((r = get_key_name(m_ptr, key_name)) != OK) 599 return r; 600 601 /* Lookup the entry. */ 602 if((dsp = lookup_entry(key_name, type)) == NULL) 603 return ESRCH; 604 605 /* Only the owner can delete. */ 606 if(strcmp(dsp->owner, source)) 607 return EPERM; 608 609 switch(type) { 610 case DSF_TYPE_U32: 611 break; 612 case DSF_TYPE_LABEL: 613 label = dsp->key; 614 615 /* Clean up subscriptions. */ 616 for (i = 0; i < NR_DS_SUBS; i++) { 617 if ((ds_subs[i].flags & DSF_IN_USE) 618 && !strcmp(ds_subs[i].owner, label)) { 619 free_sub_slot(&ds_subs[i]); 620 } 621 } 622 623 /* Clean up data entries. */ 624 for (i = 0; i < NR_DS_KEYS; i++) { 625 if ((ds_store[i].flags & DSF_IN_USE) 626 && !strcmp(ds_store[i].owner, label)) { 627 update_subscribers(&ds_store[i], 0); 628 629 ds_store[i].flags = 0; 630 } 631 } 632 break; 633 case DSF_TYPE_STR: 634 case DSF_TYPE_MEM: 635 free(dsp->u.mem.data); 636 break; 637 default: 638 return EINVAL; 639 } 640 641 /* Update subscribers having a matching subscription. */ 642 update_subscribers(dsp, 0); 643 644 /* Clear the entry. */ 645 dsp->flags = 0; 646 647 return OK; 648 } 649 650 /*===========================================================================* 651 * do_getsysinfo * 652 *===========================================================================*/ 653 int do_getsysinfo(const message *m_ptr) 654 { 655 vir_bytes src_addr; 656 size_t length; 657 int s; 658 659 switch(m_ptr->m_lsys_getsysinfo.what) { 660 case SI_DATA_STORE: 661 src_addr = (vir_bytes)ds_store; 662 length = sizeof(struct data_store) * NR_DS_KEYS; 663 break; 664 default: 665 return EINVAL; 666 } 667 668 if (length != m_ptr->m_lsys_getsysinfo.size) 669 return EINVAL; 670 671 if (OK != (s=sys_datacopy(SELF, src_addr, 672 m_ptr->m_source, m_ptr->m_lsys_getsysinfo.where, length))) { 673 printf("DS: copy failed: %d\n", s); 674 return s; 675 } 676 677 return OK; 678 } 679 680