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