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 *===========================================================================*/
alloc_data_slot(void)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 *===========================================================================*/
alloc_sub_slot(void)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 *===========================================================================*/
free_sub_slot(struct subscription * subp)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 *===========================================================================*/
lookup_entry(const char * key_name,int type)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 *===========================================================================*/
lookup_label_entry(unsigned num)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 *===========================================================================*/
lookup_sub(const char * owner)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 *===========================================================================*/
ds_getprocname(endpoint_t e)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 *===========================================================================*/
ds_getprocep(const char * s)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 *===========================================================================*/
check_auth(const struct data_store * p,endpoint_t ep,int perm)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 *===========================================================================*/
get_key_name(const message * m_ptr,char * key_name)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 *===========================================================================*/
check_sub_match(const struct subscription * subp,struct data_store * dsp,endpoint_t ep)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 *===========================================================================*/
update_subscribers(struct data_store * dsp,int set)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 *===========================================================================*/
map_service(const struct rprocpub * rpub)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 *===========================================================================*/
sef_cb_init_fresh(int UNUSED (type),sef_init_info_t * info)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 *===========================================================================*/
do_publish(message * m_ptr)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 *===========================================================================*/
do_retrieve(message * m_ptr)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 *===========================================================================*/
do_retrieve_label(const message * m_ptr)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 *===========================================================================*/
do_subscribe(message * m_ptr)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 *===========================================================================*/
do_check(message * m_ptr)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 *===========================================================================*/
do_delete(message * m_ptr)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 *===========================================================================*/
do_getsysinfo(const message * m_ptr)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