xref: /minix/minix/servers/ds/store.c (revision 9f988b79)
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 /* 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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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  *===========================================================================*/
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