xref: /minix/minix/servers/ds/store.c (revision 7f5f010b)
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 /* Allocate a new 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  *				lookup_entry				     *
42  *===========================================================================*/
43 static struct data_store *lookup_entry(const char *key_name, int type)
44 {
45 /* Lookup an existing entry by key and type. */
46   int i;
47 
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];
53   }
54 
55   return NULL;
56 }
57 
58 /*===========================================================================*
59  *			     lookup_label_entry				     *
60  *===========================================================================*/
61 static struct data_store *lookup_label_entry(unsigned num)
62 {
63 /* Lookup an existing label entry by num. */
64   int i;
65 
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];
71   }
72 
73   return NULL;
74 }
75 
76 /*===========================================================================*
77  *			      lookup_sub				     *
78  *===========================================================================*/
79 static struct subscription *lookup_sub(const char *owner)
80 {
81 /* Lookup an existing subscription given its owner. */
82   int i;
83 
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];
88   }
89 
90   return NULL;
91 }
92 
93 /*===========================================================================*
94  *				ds_getprocname				     *
95  *===========================================================================*/
96 static char *ds_getprocname(endpoint_t e)
97 {
98 /* Get a process name given its endpoint. */
99 	struct data_store *dsp;
100 
101 	static char *first_proc_name = "ds";
102 	endpoint_t first_proc_ep = DS_PROC_NR;
103 
104 	if(e == first_proc_ep)
105 		return first_proc_name;
106 
107 	if((dsp = lookup_label_entry(e)) != NULL)
108 		return dsp->key;
109 
110 	return NULL;
111 }
112 
113 /*===========================================================================*
114  *				ds_getprocep				     *
115  *===========================================================================*/
116 static endpoint_t ds_getprocep(const char *s)
117 {
118 /* Get a process endpoint given its name. */
119 	struct data_store *dsp;
120 
121 	if((dsp = lookup_entry(s, DSF_TYPE_LABEL)) != NULL)
122 		return dsp->u.u32;
123 	panic("ds_getprocep: process endpoint not found");
124 }
125 
126 /*===========================================================================*
127  *				 check_auth				     *
128  *===========================================================================*/
129 static int check_auth(const struct data_store *p, endpoint_t ep, int perm)
130 {
131 /* Check authorization for a given type of permission. */
132 	char *source;
133 
134 	if(!(p->flags & perm))
135 		return 1;
136 
137 	source = ds_getprocname(ep);
138 	return source && !strcmp(p->owner, source);
139 }
140 
141 /*===========================================================================*
142  *				get_key_name				     *
143  *===========================================================================*/
144 static int get_key_name(const message *m_ptr, char *key_name)
145 {
146 /* Get key name given an input message. */
147   int r;
148 
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;
153   }
154 
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;
162   }
163 
164   key_name[DS_MAX_KEYLEN-1] = '\0';
165 
166   return OK;
167 }
168 
169 /*===========================================================================*
170  *				check_sub_match				     *
171  *===========================================================================*/
172 static int check_sub_match(const struct subscription *subp,
173 		struct data_store *dsp, endpoint_t ep)
174 {
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;
179 }
180 
181 /*===========================================================================*
182  *			     update_subscribers				     *
183  *===========================================================================*/
184 static void update_subscribers(struct data_store *dsp, int set)
185 {
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.
188  */
189 	int i;
190 	int nr = dsp - ds_store;
191 	endpoint_t ep;
192 
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;
198 
199 		ep = ds_getprocep(ds_subs[i].owner);
200 		if(!check_sub_match(&ds_subs[i], dsp, ep))
201 			continue;
202 
203 		if(set == 1) {
204 			SET_BIT(ds_subs[i].old_subs, nr);
205 		} else {
206 			UNSET_BIT(ds_subs[i].old_subs, nr);
207 		}
208 		ipc_notify(ep);
209 	}
210 }
211 
212 /*===========================================================================*
213  *		               map_service                                   *
214  *===========================================================================*/
215 static int map_service(const struct rprocpub *rpub)
216 {
217 /* Map a new service by registering its label. */
218   struct data_store *dsp;
219 
220   /* Allocate a new data slot. */
221   if((dsp = alloc_data_slot()) == NULL) {
222 	return ENOMEM;
223   }
224 
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;
230 
231   /* Update subscribers having a matching subscription. */
232   update_subscribers(dsp, 1);
233 
234   return(OK);
235 }
236 
237 /*===========================================================================*
238  *		            sef_cb_init_fresh                                *
239  *===========================================================================*/
240 int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *info)
241 {
242 /* Initialize the data store server. */
243 	int i, r;
244 	struct rprocpub rprocpub[NR_BOOT_PROCS];
245 
246 	/* Reset data store: data and subscriptions. */
247 	for(i = 0; i < NR_DS_KEYS; i++) {
248 		ds_store[i].flags = 0;
249 	}
250 	for(i = 0; i < NR_DS_SUBS; i++) {
251 		ds_subs[i].flags = 0;
252 	}
253 
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);
258 	}
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);
263 			}
264 		}
265 	}
266 
267 	return(OK);
268 }
269 
270 /*===========================================================================*
271  *				do_publish				     *
272  *===========================================================================*/
273 int do_publish(message *m_ptr)
274 {
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;
281 
282   /* Lookup the source. */
283   source = ds_getprocname(m_ptr->m_source);
284   if(source == NULL)
285 	  return EPERM;
286 
287   /* Only RS can publish labels. */
288   if((flags & DSF_TYPE_LABEL) && m_ptr->m_source != RS_PROC_NR)
289 	  return EPERM;
290 
291   /* Get key name. */
292   if((r = get_key_name(m_ptr, key_name)) != OK)
293 	return r;
294 
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);
300 
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;
312   }
313 
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;
335 	}
336 
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;
345 	}
346 	dsp->u.mem.length = length;
347 	if(flags & DSF_TYPE_STR) {
348 		((char*)dsp->u.mem.data)[length-1] = '\0';
349 	}
350 	break;
351   default:
352 	return EINVAL;
353   }
354 
355   /* Set attributes. */
356   strcpy(dsp->key, key_name);
357   strcpy(dsp->owner, source);
358   dsp->flags = DSF_IN_USE | (flags & DSF_MASK_INTERNAL);
359 
360   /* Update subscribers having a matching subscription. */
361   update_subscribers(dsp, 1);
362 
363   return(OK);
364 }
365 
366 /*===========================================================================*
367  *				do_retrieve				     *
368  *===========================================================================*/
369 int do_retrieve(message *m_ptr)
370 {
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;
377 
378   /* Get key name. */
379   if((r = get_key_name(m_ptr, key_name)) != OK)
380 	return r;
381 
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;
387 
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;
405 	}
406 	m_ptr->m_ds_reply.val_len = length;
407 	break;
408   default:
409 	return EINVAL;
410   }
411 
412   return OK;
413 }
414 
415 /*===========================================================================*
416  *				do_retrieve_label			     *
417  *===========================================================================*/
418 int do_retrieve_label(const message *m_ptr)
419 {
420   struct data_store *dsp;
421   int r;
422 
423   /* Lookup the label entry. */
424   if((dsp = lookup_label_entry(m_ptr->m_ds_req.val_in.ep)) == NULL)
425 	return ESRCH;
426 
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;
434   }
435 
436   return OK;
437 }
438 
439 /*===========================================================================*
440  *				do_subscribe				     *
441  *===========================================================================*/
442 int do_subscribe(message *m_ptr)
443 {
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;
450 
451   /* Find the owner. */
452   owner = ds_getprocname(m_ptr->m_source);
453   if(owner == NULL)
454 	  return ESRCH;
455 
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;
464   }
465 
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.
469    */
470   regex[0] = '^';
471   if((r = get_key_name(m_ptr, regex+1)) != OK)
472 	return r;
473   strcat(regex, "$");
474 
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;
480   }
481 
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;
486 
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;
491 
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;
502 
503 		SET_BIT(subp->old_subs, i);
504 		match_found = TRUE;
505 	}
506 
507 	/* Notify in case of match. */
508 	if(match_found)
509 		ipc_notify(m_ptr->m_source);
510   }
511 
512   return OK;
513 }
514 
515 /*===========================================================================*
516  *				do_check				     *
517  *===========================================================================*/
518 int do_check(message *m_ptr)
519 {
520   struct subscription *subp;
521   char *owner;
522   endpoint_t entry_owner_e;
523   int r, i;
524 
525   /* Find the subscription owner. */
526   owner = ds_getprocname(m_ptr->m_source);
527   if(owner == NULL)
528 	  return ESRCH;
529 
530   /* Lookup the owner's subscription. */
531   if((subp = lookup_sub(owner)) == NULL)
532 	return ESRCH;
533 
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;
538   }
539   if(i == NR_DS_KEYS)
540 	return ENOENT;
541 
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;
549   }
550 
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;
555 
556   /* Mark the entry as no longer updated for the subscriber. */
557   UNSET_BIT(subp->old_subs, i);
558 
559   return OK;
560 }
561 
562 /*===========================================================================*
563  *				do_delete				     *
564  *===========================================================================*/
565 int do_delete(message *m_ptr)
566 {
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;
573 
574   /* Lookup the source. */
575   source = ds_getprocname(m_ptr->m_source);
576   if(source == NULL)
577 	  return EPERM;
578 
579   /* Get key name. */
580   if((r = get_key_name(m_ptr, key_name)) != OK)
581 	return r;
582 
583   /* Lookup the entry. */
584   if((dsp = lookup_entry(key_name, type)) == NULL)
585 	return ESRCH;
586 
587   /* Only the owner can delete. */
588   if(strcmp(dsp->owner, source))
589 	return EPERM;
590 
591   switch(type) {
592   case DSF_TYPE_U32:
593 	break;
594   case DSF_TYPE_LABEL:
595 	label = dsp->key;
596 
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;
602 		}
603 	}
604 
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);
610 
611 			ds_store[i].flags = 0;
612 		}
613 	}
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;
621   }
622 
623   /* Update subscribers having a matching subscription. */
624   update_subscribers(dsp, 0);
625 
626   /* Clear the entry. */
627   dsp->flags = 0;
628 
629   return OK;
630 }
631 
632 /*===========================================================================*
633  *				do_getsysinfo				     *
634  *===========================================================================*/
635 int do_getsysinfo(const message *m_ptr)
636 {
637   vir_bytes src_addr;
638   size_t length;
639   int s;
640 
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;
648   }
649 
650   if (length != m_ptr->m_lsys_getsysinfo.size)
651 	return EINVAL;
652 
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;
657   }
658 
659   return OK;
660 }
661 
662