kernel: vm kernel call can't suspend
[minix.git] / servers / ds / store.c
blob06887bcfedc6e053bc354656e05c2e06eeacf948
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->DS_KEY_LEN > DS_MAX_KEYLEN || m_ptr->DS_KEY_LEN < 2) {
150 printf("DS: bogus key length (%d) from %d\n", m_ptr->DS_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->DS_KEY_GRANT, 0,
158 (vir_bytes) key_name, m_ptr->DS_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 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->DS_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->DS_VAL);
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 case DSF_TYPE_LABEL:
318 dsp->u.u32 = m_ptr->DS_VAL;
319 break;
320 case DSF_TYPE_STR:
321 case DSF_TYPE_MEM:
322 length = m_ptr->DS_VAL_LEN;
323 /* Allocate a new data buffer if necessary. */
324 if(!(dsp->flags & DSF_IN_USE)) {
325 if((dsp->u.mem.data = malloc(length)) == NULL)
326 return ENOMEM;
327 dsp->u.mem.reallen = length;
328 } else if(length > dsp->u.mem.reallen) {
329 free(dsp->u.mem.data);
330 if((dsp->u.mem.data = malloc(length)) == NULL)
331 return ENOMEM;
332 dsp->u.mem.reallen = length;
335 /* Copy the memory range. */
336 r = sys_safecopyfrom(m_ptr->m_source, (cp_grant_id_t) m_ptr->DS_VAL,
337 0, (vir_bytes) dsp->u.mem.data, length);
338 if(r != OK) {
339 printf("DS: publish: memory map/copy failed from %d: %d\n",
340 m_ptr->m_source, r);
341 free(dsp->u.mem.data);
342 return r;
344 dsp->u.mem.length = length;
345 if(flags & DSF_TYPE_STR) {
346 ((char*)dsp->u.mem.data)[length-1] = '\0';
348 break;
349 default:
350 return EINVAL;
353 /* Set attributes. */
354 strcpy(dsp->key, key_name);
355 strcpy(dsp->owner, source);
356 dsp->flags = DSF_IN_USE | (flags & DSF_MASK_INTERNAL);
358 /* Update subscribers having a matching subscription. */
359 update_subscribers(dsp, 1);
361 return(OK);
364 /*===========================================================================*
365 * do_retrieve *
366 *===========================================================================*/
367 int do_retrieve(message *m_ptr)
369 struct data_store *dsp;
370 char key_name[DS_MAX_KEYLEN];
371 int flags = m_ptr->DS_FLAGS;
372 int type = flags & DSF_MASK_TYPE;
373 size_t length;
374 int r;
376 /* Get key name. */
377 if((r = get_key_name(m_ptr, key_name)) != OK)
378 return r;
380 /* Lookup the entry. */
381 if((dsp = lookup_entry(key_name, type)) == NULL)
382 return ESRCH;
383 if(!check_auth(dsp, m_ptr->m_source, DSF_PRIV_RETRIEVE))
384 return EPERM;
386 /* Copy the requested data. */
387 switch(type) {
388 case DSF_TYPE_U32:
389 case DSF_TYPE_LABEL:
390 m_ptr->DS_VAL = dsp->u.u32;
391 break;
392 case DSF_TYPE_STR:
393 case DSF_TYPE_MEM:
394 length = MIN(m_ptr->DS_VAL_LEN, dsp->u.mem.length);
395 r = sys_safecopyto(m_ptr->m_source, (cp_grant_id_t) m_ptr->DS_VAL, 0,
396 (vir_bytes) dsp->u.mem.data, length);
397 if(r != OK) {
398 printf("DS: retrieve: copy failed to %d: %d\n",
399 m_ptr->m_source, r);
400 return r;
402 m_ptr->DS_VAL_LEN = length;
403 break;
404 default:
405 return EINVAL;
408 return OK;
411 /*===========================================================================*
412 * do_retrieve_label *
413 *===========================================================================*/
414 int do_retrieve_label(const message *m_ptr)
416 struct data_store *dsp;
417 int r;
419 /* Lookup the label entry. */
420 if((dsp = lookup_label_entry(m_ptr->DS_VAL)) == NULL)
421 return ESRCH;
423 /* Copy the key name. */
424 r = sys_safecopyto(m_ptr->m_source,
425 (cp_grant_id_t) m_ptr->DS_KEY_GRANT, (vir_bytes) 0,
426 (vir_bytes) dsp->key, strlen(dsp->key) + 1);
427 if(r != OK) {
428 printf("DS: copy failed from %d: %d\n", m_ptr->m_source, r);
429 return r;
432 return OK;
435 /*===========================================================================*
436 * do_subscribe *
437 *===========================================================================*/
438 int do_subscribe(message *m_ptr)
440 char regex[DS_MAX_KEYLEN+2];
441 struct subscription *subp;
442 char errbuf[80];
443 char *owner;
444 int type_set;
445 int r, e, b;
447 /* Find the owner. */
448 owner = ds_getprocname(m_ptr->m_source);
449 if(owner == NULL)
450 return ESRCH;
452 /* See if the owner already has an existing subscription. */
453 if((subp = lookup_sub(owner)) == NULL) {
454 /* The subscription doesn't exist, allocate a new one. */
455 if((subp = alloc_sub_slot()) == NULL)
456 return EAGAIN;
457 } else if(!(m_ptr->DS_FLAGS & DSF_OVERWRITE)) {
458 /* The subscription exists but we can't overwrite, return error. */
459 return EEXIST;
462 /* Copy key name from the caller. Anchor the subscription with "^regexp$" so
463 * substrings don't match. The caller will probably not expect this,
464 * and the usual case is for a complete match.
466 regex[0] = '^';
467 if((r = get_key_name(m_ptr, regex+1)) != OK)
468 return r;
469 strcat(regex, "$");
471 /* Compile regular expression. */
472 if((e=regcomp(&subp->regex, regex, REG_EXTENDED)) != 0) {
473 regerror(e, &subp->regex, errbuf, sizeof(errbuf));
474 printf("DS: subscribe: regerror: %s\n", errbuf);
475 return EINVAL;
478 /* If type_set = 0, then subscribe all types. */
479 type_set = m_ptr->DS_FLAGS & DSF_MASK_TYPE;
480 if(type_set == 0)
481 type_set = DSF_MASK_TYPE;
483 subp->flags = DSF_IN_USE | type_set;
484 strcpy(subp->owner, owner);
485 for(b = 0; b < BITMAP_CHUNKS(NR_DS_KEYS); b++)
486 subp->old_subs[b] = 0;
488 /* See if caller requested an instant initial list. */
489 if(m_ptr->DS_FLAGS & DSF_INITIAL) {
490 int i, match_found = FALSE;
491 for(i = 0; i < NR_DS_KEYS; i++) {
492 if(!(ds_store[i].flags & DSF_IN_USE))
493 continue;
494 if(!(ds_store[i].flags & type_set))
495 continue;
496 if(!check_sub_match(subp, &ds_store[i], m_ptr->m_source))
497 continue;
499 SET_BIT(subp->old_subs, i);
500 match_found = TRUE;
503 /* Notify in case of match. */
504 if(match_found)
505 notify(m_ptr->m_source);
508 return OK;
511 /*===========================================================================*
512 * do_check *
513 *===========================================================================*/
514 int do_check(message *m_ptr)
516 struct subscription *subp;
517 char *owner;
518 endpoint_t entry_owner_e;
519 int r, i;
521 /* Find the subscription owner. */
522 owner = ds_getprocname(m_ptr->m_source);
523 if(owner == NULL)
524 return ESRCH;
526 /* Lookup the owner's subscription. */
527 if((subp = lookup_sub(owner)) == NULL)
528 return ESRCH;
530 /* Look for an updated entry the subscriber is interested in. */
531 for(i = 0; i < NR_DS_KEYS; i++) {
532 if(GET_BIT(subp->old_subs, i))
533 break;
535 if(i == NR_DS_KEYS)
536 return ENOENT;
538 /* Copy the key name. */
539 r = sys_safecopyto(m_ptr->m_source,
540 (cp_grant_id_t) m_ptr->DS_KEY_GRANT, (vir_bytes) 0,
541 (vir_bytes) ds_store[i].key, strlen(ds_store[i].key) + 1);
542 if(r != OK) {
543 printf("DS: check: copy failed from %d: %d\n", m_ptr->m_source, r);
544 return r;
547 /* Copy the type and the owner of the original entry. */
548 entry_owner_e = ds_getprocep(ds_store[i].owner);
549 m_ptr->DS_FLAGS = ds_store[i].flags & DSF_MASK_TYPE;
550 m_ptr->DS_OWNER = entry_owner_e;
552 /* Mark the entry as no longer updated for the subscriber. */
553 UNSET_BIT(subp->old_subs, i);
555 return OK;
558 /*===========================================================================*
559 * do_delete *
560 *===========================================================================*/
561 int do_delete(message *m_ptr)
563 struct data_store *dsp;
564 char key_name[DS_MAX_KEYLEN];
565 char *source;
566 char *label;
567 int type = m_ptr->DS_FLAGS & DSF_MASK_TYPE;
568 int i, r;
570 /* Lookup the source. */
571 source = ds_getprocname(m_ptr->m_source);
572 if(source == NULL)
573 return EPERM;
575 /* Get key name. */
576 if((r = get_key_name(m_ptr, key_name)) != OK)
577 return r;
579 /* Lookup the entry. */
580 if((dsp = lookup_entry(key_name, type)) == NULL)
581 return ESRCH;
583 /* Only the owner can delete. */
584 if(strcmp(dsp->owner, source))
585 return EPERM;
587 switch(type) {
588 case DSF_TYPE_U32:
589 break;
590 case DSF_TYPE_LABEL:
591 label = dsp->key;
593 /* Clean up subscriptions. */
594 for (i = 0; i < NR_DS_SUBS; i++) {
595 if ((ds_subs[i].flags & DSF_IN_USE)
596 && !strcmp(ds_subs[i].owner, label)) {
597 ds_subs[i].flags = 0;
601 /* Clean up data entries. */
602 for (i = 0; i < NR_DS_KEYS; i++) {
603 if ((ds_store[i].flags & DSF_IN_USE)
604 && !strcmp(ds_store[i].owner, label)) {
605 update_subscribers(&ds_store[i], 0);
607 ds_store[i].flags = 0;
610 break;
611 case DSF_TYPE_STR:
612 case DSF_TYPE_MEM:
613 free(dsp->u.mem.data);
614 break;
615 default:
616 return EINVAL;
619 /* Update subscribers having a matching subscription. */
620 update_subscribers(dsp, 0);
622 /* Clear the entry. */
623 dsp->flags = 0;
625 return OK;
628 /*===========================================================================*
629 * do_getsysinfo *
630 *===========================================================================*/
631 int do_getsysinfo(const message *m_ptr)
633 vir_bytes src_addr;
634 size_t length;
635 int s;
637 switch(m_ptr->SI_WHAT) {
638 case SI_DATA_STORE:
639 src_addr = (vir_bytes)ds_store;
640 length = sizeof(struct data_store) * NR_DS_KEYS;
641 break;
642 default:
643 return EINVAL;
646 if (length != m_ptr->SI_SIZE)
647 return EINVAL;
649 if (OK != (s=sys_datacopy(SELF, src_addr,
650 m_ptr->m_source, (vir_bytes)m_ptr->SI_WHERE, length))) {
651 printf("DS: copy failed: %d\n", s);
652 return s;
655 return OK;