tools/llvm: Do not build with symbols
[minix3.git] / minix / servers / ds / store.c
blobe6fb5e10c029a8a123c5208545dd8240a5b285a0
1 #include "inc.h"
2 #include "store.h"
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];
8 /*===========================================================================*
9 * alloc_data_slot *
10 *===========================================================================*/
11 static struct data_store *alloc_data_slot(void)
13 /* Allocate a new data slot. */
14 int i;
16 for (i = 0; i < NR_DS_KEYS; i++) {
17 if (!(ds_store[i].flags & DSF_IN_USE))
18 return &ds_store[i];
21 return NULL;
24 /*===========================================================================*
25 * alloc_sub_slot *
26 *===========================================================================*/
27 static struct subscription *alloc_sub_slot(void)
29 /* Allocate a new subscription slot. */
30 int i;
32 for (i = 0; i < NR_DS_SUBS; i++) {
33 if (!(ds_subs[i].flags & DSF_IN_USE))
34 return &ds_subs[i];
37 return NULL;
40 /*===========================================================================*
41 * lookup_entry *
42 *===========================================================================*/
43 static struct data_store *lookup_entry(const char *key_name, int type)
45 /* Lookup an existing entry by key and type. */
46 int i;
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];
55 return NULL;
58 /*===========================================================================*
59 * lookup_label_entry *
60 *===========================================================================*/
61 static struct data_store *lookup_label_entry(unsigned num)
63 /* Lookup an existing label entry by num. */
64 int i;
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];
73 return NULL;
76 /*===========================================================================*
77 * lookup_sub *
78 *===========================================================================*/
79 static struct subscription *lookup_sub(const char *owner)
81 /* Lookup an existing subscription given its owner. */
82 int i;
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];
90 return NULL;
93 /*===========================================================================*
94 * ds_getprocname *
95 *===========================================================================*/
96 static char *ds_getprocname(endpoint_t e)
98 /* Get a process name given its endpoint. */
99 struct data_store *dsp;
101 static char *first_proc_name = "ds";
102 endpoint_t first_proc_ep = DS_PROC_NR;
104 if(e == first_proc_ep)
105 return first_proc_name;
107 if((dsp = lookup_label_entry(e)) != NULL)
108 return dsp->key;
110 return NULL;
113 /*===========================================================================*
114 * ds_getprocep *
115 *===========================================================================*/
116 static endpoint_t ds_getprocep(const char *s)
118 /* Get a process endpoint given its name. */
119 struct data_store *dsp;
121 if((dsp = lookup_entry(s, DSF_TYPE_LABEL)) != NULL)
122 return dsp->u.u32;
123 panic("ds_getprocep: process endpoint not found");
126 /*===========================================================================*
127 * check_auth *
128 *===========================================================================*/
129 static int check_auth(const struct data_store *p, endpoint_t ep, int perm)
131 /* Check authorization for a given type of permission. */
132 char *source;
134 if(!(p->flags & perm))
135 return 1;
137 source = ds_getprocname(ep);
138 return source && !strcmp(p->owner, source);
141 /*===========================================================================*
142 * get_key_name *
143 *===========================================================================*/
144 static int get_key_name(const message *m_ptr, char *key_name)
146 /* Get key name given an input message. */
147 int r;
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;
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;
164 key_name[DS_MAX_KEYLEN-1] = '\0';
166 return OK;
169 /*===========================================================================*
170 * check_sub_match *
171 *===========================================================================*/
172 static int check_sub_match(const struct subscription *subp,
173 struct data_store *dsp, endpoint_t ep)
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;
181 /*===========================================================================*
182 * update_subscribers *
183 *===========================================================================*/
184 static void update_subscribers(struct data_store *dsp, int set)
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.
189 int i;
190 int nr = dsp - ds_store;
191 endpoint_t ep;
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;
199 ep = ds_getprocep(ds_subs[i].owner);
200 if(!check_sub_match(&ds_subs[i], dsp, ep))
201 continue;
203 if(set == 1) {
204 SET_BIT(ds_subs[i].old_subs, nr);
205 } else {
206 UNSET_BIT(ds_subs[i].old_subs, nr);
208 ipc_notify(ep);
212 /*===========================================================================*
213 * map_service *
214 *===========================================================================*/
215 static int map_service(const struct rprocpub *rpub)
217 /* Map a new service by registering its label. */
218 struct data_store *dsp;
220 /* Allocate a new data slot. */
221 if((dsp = alloc_data_slot()) == NULL) {
222 return ENOMEM;
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;
231 /* Update subscribers having a matching subscription. */
232 update_subscribers(dsp, 1);
234 return(OK);
237 /*===========================================================================*
238 * sef_cb_init_fresh *
239 *===========================================================================*/
240 int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *info)
242 /* Initialize the data store server. */
243 int i, r;
244 struct rprocpub rprocpub[NR_BOOT_PROCS];
246 /* Reset data store: data and subscriptions. */
247 for(i = 0; i < NR_DS_KEYS; i++) {
248 ds_store[i].flags = 0;
250 for(i = 0; i < NR_DS_SUBS; i++) {
251 ds_subs[i].flags = 0;
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);
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);
267 return(OK);
270 /*===========================================================================*
271 * do_publish *
272 *===========================================================================*/
273 int do_publish(message *m_ptr)
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;
282 /* Lookup the source. */
283 source = ds_getprocname(m_ptr->m_source);
284 if(source == NULL)
285 return EPERM;
287 /* Only RS can publish labels. */
288 if((flags & DSF_TYPE_LABEL) && m_ptr->m_source != RS_PROC_NR)
289 return EPERM;
291 /* Get key name. */
292 if((r = get_key_name(m_ptr, key_name)) != OK)
293 return r;
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);
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;
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;
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;
346 dsp->u.mem.length = length;
347 if(flags & DSF_TYPE_STR) {
348 ((char*)dsp->u.mem.data)[length-1] = '\0';
350 break;
351 default:
352 return EINVAL;
355 /* Set attributes. */
356 strcpy(dsp->key, key_name);
357 strcpy(dsp->owner, source);
358 dsp->flags = DSF_IN_USE | (flags & DSF_MASK_INTERNAL);
360 /* Update subscribers having a matching subscription. */
361 update_subscribers(dsp, 1);
363 return(OK);
366 /*===========================================================================*
367 * do_retrieve *
368 *===========================================================================*/
369 int do_retrieve(message *m_ptr)
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;
378 /* Get key name. */
379 if((r = get_key_name(m_ptr, key_name)) != OK)
380 return r;
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;
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;
406 m_ptr->m_ds_reply.val_len = length;
407 break;
408 default:
409 return EINVAL;
412 return OK;
415 /*===========================================================================*
416 * do_retrieve_label *
417 *===========================================================================*/
418 int do_retrieve_label(const message *m_ptr)
420 struct data_store *dsp;
421 int r;
423 /* Lookup the label entry. */
424 if((dsp = lookup_label_entry(m_ptr->m_ds_req.val_in.ep)) == NULL)
425 return ESRCH;
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;
436 return OK;
439 /*===========================================================================*
440 * do_subscribe *
441 *===========================================================================*/
442 int do_subscribe(message *m_ptr)
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;
451 /* Find the owner. */
452 owner = ds_getprocname(m_ptr->m_source);
453 if(owner == NULL)
454 return ESRCH;
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;
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.
470 regex[0] = '^';
471 if((r = get_key_name(m_ptr, regex+1)) != OK)
472 return r;
473 strcat(regex, "$");
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;
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;
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;
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;
503 SET_BIT(subp->old_subs, i);
504 match_found = TRUE;
507 /* Notify in case of match. */
508 if(match_found)
509 ipc_notify(m_ptr->m_source);
512 return OK;
515 /*===========================================================================*
516 * do_check *
517 *===========================================================================*/
518 int do_check(message *m_ptr)
520 struct subscription *subp;
521 char *owner;
522 endpoint_t entry_owner_e;
523 int r, i;
525 /* Find the subscription owner. */
526 owner = ds_getprocname(m_ptr->m_source);
527 if(owner == NULL)
528 return ESRCH;
530 /* Lookup the owner's subscription. */
531 if((subp = lookup_sub(owner)) == NULL)
532 return ESRCH;
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;
539 if(i == NR_DS_KEYS)
540 return ENOENT;
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;
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;
556 /* Mark the entry as no longer updated for the subscriber. */
557 UNSET_BIT(subp->old_subs, i);
559 return OK;
562 /*===========================================================================*
563 * do_delete *
564 *===========================================================================*/
565 int do_delete(message *m_ptr)
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;
574 /* Lookup the source. */
575 source = ds_getprocname(m_ptr->m_source);
576 if(source == NULL)
577 return EPERM;
579 /* Get key name. */
580 if((r = get_key_name(m_ptr, key_name)) != OK)
581 return r;
583 /* Lookup the entry. */
584 if((dsp = lookup_entry(key_name, type)) == NULL)
585 return ESRCH;
587 /* Only the owner can delete. */
588 if(strcmp(dsp->owner, source))
589 return EPERM;
591 switch(type) {
592 case DSF_TYPE_U32:
593 break;
594 case DSF_TYPE_LABEL:
595 label = dsp->key;
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;
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);
611 ds_store[i].flags = 0;
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;
623 /* Update subscribers having a matching subscription. */
624 update_subscribers(dsp, 0);
626 /* Clear the entry. */
627 dsp->flags = 0;
629 return OK;
632 /*===========================================================================*
633 * do_getsysinfo *
634 *===========================================================================*/
635 int do_getsysinfo(const message *m_ptr)
637 vir_bytes src_addr;
638 size_t length;
639 int s;
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;
650 if (length != m_ptr->m_lsys_getsysinfo.size)
651 return EINVAL;
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;
659 return OK;