Drop main() prototype. Syncs with NetBSD-8
[minix.git] / minix / servers / ds / store.c
blobf9d2407ac1df1a418737ed54ab3583f402e591ac
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 /* Return a free 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 * free_sub_slot *
42 *===========================================================================*/
43 static void free_sub_slot(struct subscription *subp)
45 /* Clean up a previously successfully) allocated subscription slot. */
46 assert(subp->flags & DSF_IN_USE);
48 regfree(&subp->regex);
49 memset(&subp->regex, 0, sizeof(subp->regex));
51 subp->flags = 0;
54 /*===========================================================================*
55 * lookup_entry *
56 *===========================================================================*/
57 static struct data_store *lookup_entry(const char *key_name, int type)
59 /* Lookup an existing entry by key and type. */
60 int i;
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];
69 return NULL;
72 /*===========================================================================*
73 * lookup_label_entry *
74 *===========================================================================*/
75 static struct data_store *lookup_label_entry(unsigned num)
77 /* Lookup an existing label entry by num. */
78 int i;
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];
87 return NULL;
90 /*===========================================================================*
91 * lookup_sub *
92 *===========================================================================*/
93 static struct subscription *lookup_sub(const char *owner)
95 /* Lookup an existing subscription given its owner. */
96 int i;
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];
104 return NULL;
107 /*===========================================================================*
108 * ds_getprocname *
109 *===========================================================================*/
110 static char *ds_getprocname(endpoint_t e)
112 /* Get a process name given its endpoint. */
113 struct data_store *dsp;
115 static char *first_proc_name = "ds";
116 endpoint_t first_proc_ep = DS_PROC_NR;
118 if(e == first_proc_ep)
119 return first_proc_name;
121 if((dsp = lookup_label_entry(e)) != NULL)
122 return dsp->key;
124 return NULL;
127 /*===========================================================================*
128 * ds_getprocep *
129 *===========================================================================*/
130 static endpoint_t ds_getprocep(const char *s)
132 /* Get a process endpoint given its name. */
133 struct data_store *dsp;
135 if((dsp = lookup_entry(s, DSF_TYPE_LABEL)) != NULL)
136 return dsp->u.u32;
137 panic("ds_getprocep: process endpoint not found");
140 /*===========================================================================*
141 * check_auth *
142 *===========================================================================*/
143 static int check_auth(const struct data_store *p, endpoint_t ep, int perm)
145 /* Check authorization for a given type of permission. */
146 char *source;
148 if(!(p->flags & perm))
149 return 1;
151 source = ds_getprocname(ep);
152 return source && !strcmp(p->owner, source);
155 /*===========================================================================*
156 * get_key_name *
157 *===========================================================================*/
158 static int get_key_name(const message *m_ptr, char *key_name)
160 /* Get key name given an input message. */
161 int r;
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;
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;
178 key_name[DS_MAX_KEYLEN-1] = '\0';
180 return OK;
183 /*===========================================================================*
184 * check_sub_match *
185 *===========================================================================*/
186 static int check_sub_match(const struct subscription *subp,
187 struct data_store *dsp, endpoint_t ep)
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;
195 /*===========================================================================*
196 * update_subscribers *
197 *===========================================================================*/
198 static void update_subscribers(struct data_store *dsp, int set)
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.
203 int i;
204 int nr = dsp - ds_store;
205 endpoint_t ep;
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;
213 ep = ds_getprocep(ds_subs[i].owner);
214 if(!check_sub_match(&ds_subs[i], dsp, ep))
215 continue;
217 if(set == 1) {
218 SET_BIT(ds_subs[i].old_subs, nr);
219 } else {
220 UNSET_BIT(ds_subs[i].old_subs, nr);
222 ipc_notify(ep);
226 /*===========================================================================*
227 * map_service *
228 *===========================================================================*/
229 static int map_service(const struct rprocpub *rpub)
231 /* Map a new service by registering its label. */
232 struct data_store *dsp;
234 /* Allocate a new data slot. */
235 if((dsp = alloc_data_slot()) == NULL) {
236 return ENOMEM;
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;
245 /* Update subscribers having a matching subscription. */
246 update_subscribers(dsp, 1);
248 return(OK);
251 /*===========================================================================*
252 * sef_cb_init_fresh *
253 *===========================================================================*/
254 int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *info)
256 /* Initialize the data store server. */
257 int i, r;
258 struct rprocpub rprocpub[NR_BOOT_PROCS];
260 /* Reset data store: data and subscriptions. */
261 for(i = 0; i < NR_DS_KEYS; i++) {
262 ds_store[i].flags = 0;
264 for(i = 0; i < NR_DS_SUBS; i++) {
265 ds_subs[i].flags = 0;
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);
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);
281 return(OK);
284 /*===========================================================================*
285 * do_publish *
286 *===========================================================================*/
287 int do_publish(message *m_ptr)
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;
296 /* Lookup the source. */
297 source = ds_getprocname(m_ptr->m_source);
298 if(source == NULL)
299 return EPERM;
301 /* Only RS can publish labels. */
302 if((flags & DSF_TYPE_LABEL) && m_ptr->m_source != RS_PROC_NR)
303 return EPERM;
305 /* Get key name. */
306 if((r = get_key_name(m_ptr, key_name)) != OK)
307 return r;
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);
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;
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;
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;
360 dsp->u.mem.length = length;
361 if(flags & DSF_TYPE_STR) {
362 ((char*)dsp->u.mem.data)[length-1] = '\0';
364 break;
365 default:
366 return EINVAL;
369 /* Set attributes. */
370 strcpy(dsp->key, key_name);
371 strcpy(dsp->owner, source);
372 dsp->flags = DSF_IN_USE | (flags & DSF_MASK_INTERNAL);
374 /* Update subscribers having a matching subscription. */
375 update_subscribers(dsp, 1);
377 return(OK);
380 /*===========================================================================*
381 * do_retrieve *
382 *===========================================================================*/
383 int do_retrieve(message *m_ptr)
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;
392 /* Get key name. */
393 if((r = get_key_name(m_ptr, key_name)) != OK)
394 return r;
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;
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;
420 m_ptr->m_ds_reply.val_len = length;
421 break;
422 default:
423 return EINVAL;
426 return OK;
429 /*===========================================================================*
430 * do_retrieve_label *
431 *===========================================================================*/
432 int do_retrieve_label(const message *m_ptr)
434 struct data_store *dsp;
435 int r;
437 /* Lookup the label entry. */
438 if((dsp = lookup_label_entry(m_ptr->m_ds_req.val_in.ep)) == NULL)
439 return ESRCH;
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;
450 return OK;
453 /*===========================================================================*
454 * do_subscribe *
455 *===========================================================================*/
456 int do_subscribe(message *m_ptr)
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;
465 /* Find the owner. */
466 owner = ds_getprocname(m_ptr->m_source);
467 if(owner == NULL)
468 return ESRCH;
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);
479 /* Find a free subscription slot. */
480 if ((subp = alloc_sub_slot()) == NULL)
481 return EAGAIN;
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.
487 regex[0] = '^';
488 if((r = get_key_name(m_ptr, regex+1)) != OK)
489 return r;
490 strcat(regex, "$");
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;
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;
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;
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;
521 SET_BIT(subp->old_subs, i);
522 match_found = TRUE;
525 /* Notify in case of match. */
526 if(match_found)
527 ipc_notify(m_ptr->m_source);
530 return OK;
533 /*===========================================================================*
534 * do_check *
535 *===========================================================================*/
536 int do_check(message *m_ptr)
538 struct subscription *subp;
539 char *owner;
540 endpoint_t entry_owner_e;
541 int r, i;
543 /* Find the subscription owner. */
544 owner = ds_getprocname(m_ptr->m_source);
545 if(owner == NULL)
546 return ESRCH;
548 /* Lookup the owner's subscription. */
549 if((subp = lookup_sub(owner)) == NULL)
550 return ESRCH;
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;
557 if(i == NR_DS_KEYS)
558 return ENOENT;
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;
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;
574 /* Mark the entry as no longer updated for the subscriber. */
575 UNSET_BIT(subp->old_subs, i);
577 return OK;
580 /*===========================================================================*
581 * do_delete *
582 *===========================================================================*/
583 int do_delete(message *m_ptr)
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;
592 /* Lookup the source. */
593 source = ds_getprocname(m_ptr->m_source);
594 if(source == NULL)
595 return EPERM;
597 /* Get key name. */
598 if((r = get_key_name(m_ptr, key_name)) != OK)
599 return r;
601 /* Lookup the entry. */
602 if((dsp = lookup_entry(key_name, type)) == NULL)
603 return ESRCH;
605 /* Only the owner can delete. */
606 if(strcmp(dsp->owner, source))
607 return EPERM;
609 switch(type) {
610 case DSF_TYPE_U32:
611 break;
612 case DSF_TYPE_LABEL:
613 label = dsp->key;
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]);
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);
629 ds_store[i].flags = 0;
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;
641 /* Update subscribers having a matching subscription. */
642 update_subscribers(dsp, 0);
644 /* Clear the entry. */
645 dsp->flags = 0;
647 return OK;
650 /*===========================================================================*
651 * do_getsysinfo *
652 *===========================================================================*/
653 int do_getsysinfo(const message *m_ptr)
655 vir_bytes src_addr;
656 size_t length;
657 int s;
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;
668 if (length != m_ptr->m_lsys_getsysinfo.size)
669 return EINVAL;
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;
677 return OK;