source: mainline/uspace/lib/c/generic/loc.c@ f0cc1c64

Last change on this file since f0cc1c64 was ca48672, checked in by Jiri Svoboda <jiri@…>, 8 days ago

loc_service_register() needs to take a port ID argument.

  • Property mode set to 100644
File size: 19.1 KB
Line 
1/*
2 * Copyright (c) 2025 Jiri Svoboda
3 * Copyright (c) 2007 Josef Cejka
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <str.h>
31#include <ipc/services.h>
32#include <ns.h>
33#include <ipc/loc.h>
34#include <loc.h>
35#include <fibril_synch.h>
36#include <async.h>
37#include <errno.h>
38#include <stdlib.h>
39#include <stdbool.h>
40
41static FIBRIL_MUTEX_INITIALIZE(loc_cons_block_mutex);
42static FIBRIL_MUTEX_INITIALIZE(loc_consumer_mutex);
43
44static FIBRIL_MUTEX_INITIALIZE(loc_callback_mutex);
45static bool loc_callback_created = false;
46static loc_cat_change_cb_t cat_change_cb = NULL;
47static void *cat_change_arg = NULL;
48
49static async_sess_t *loc_cons_block_sess = NULL;
50static async_sess_t *loc_consumer_sess = NULL;
51
52static void loc_cb_conn(ipc_call_t *icall, void *arg)
53{
54 while (true) {
55 ipc_call_t call;
56 async_get_call(&call);
57
58 if (!ipc_get_imethod(&call)) {
59 async_answer_0(&call, EOK);
60 return;
61 }
62
63 switch (ipc_get_imethod(&call)) {
64 case LOC_EVENT_CAT_CHANGE:
65 fibril_mutex_lock(&loc_callback_mutex);
66 loc_cat_change_cb_t cb_fun = cat_change_cb;
67 void *cb_arg = cat_change_arg;
68 fibril_mutex_unlock(&loc_callback_mutex);
69
70 async_answer_0(&call, EOK);
71
72 if (cb_fun != NULL)
73 (*cb_fun)(cb_arg);
74
75 break;
76 default:
77 async_answer_0(&call, ENOTSUP);
78 }
79 }
80}
81
82static void clone_session(fibril_mutex_t *mtx, async_sess_t *src,
83 async_sess_t **dst)
84{
85 fibril_mutex_lock(mtx);
86
87 if ((*dst == NULL) && (src != NULL))
88 *dst = src;
89
90 fibril_mutex_unlock(mtx);
91}
92
93/** Create callback
94 *
95 * Must be called with loc_callback_mutex locked.
96 *
97 * @return EOK on success.
98 *
99 */
100static errno_t loc_callback_create(void)
101{
102 if (!loc_callback_created) {
103 async_exch_t *exch =
104 loc_exchange_begin_blocking();
105
106 ipc_call_t answer;
107 aid_t req = async_send_0(exch, LOC_CALLBACK_CREATE, &answer);
108
109 port_id_t port;
110 errno_t rc = async_create_callback_port(exch, INTERFACE_LOC_CB, 0, 0,
111 loc_cb_conn, NULL, &port);
112
113 loc_exchange_end(exch);
114
115 if (rc != EOK)
116 return rc;
117
118 errno_t retval;
119 async_wait_for(req, &retval);
120 if (retval != EOK)
121 return retval;
122
123 loc_callback_created = true;
124 }
125
126 return EOK;
127}
128
129/** Start an async exchange on the loc session (blocking).
130 *
131 * @return New exchange.
132 *
133 */
134async_exch_t *loc_exchange_begin_blocking(void)
135{
136 fibril_mutex_lock(&loc_cons_block_mutex);
137
138 while (loc_cons_block_sess == NULL) {
139 clone_session(&loc_consumer_mutex, loc_consumer_sess,
140 &loc_cons_block_sess);
141
142 if (loc_cons_block_sess == NULL)
143 loc_cons_block_sess =
144 service_connect_blocking(SERVICE_LOC,
145 INTERFACE_LOC_CONSUMER, 0, NULL);
146 }
147
148 fibril_mutex_unlock(&loc_cons_block_mutex);
149
150 clone_session(&loc_consumer_mutex, loc_cons_block_sess,
151 &loc_consumer_sess);
152
153 return async_exchange_begin(loc_cons_block_sess);
154}
155
156/** Start an async exchange on the loc session.
157 *
158 * @return New exchange.
159 *
160 */
161async_exch_t *loc_exchange_begin(void)
162{
163 fibril_mutex_lock(&loc_consumer_mutex);
164
165 if (loc_consumer_sess == NULL)
166 loc_consumer_sess =
167 service_connect(SERVICE_LOC,
168 INTERFACE_LOC_CONSUMER, 0, NULL);
169
170 fibril_mutex_unlock(&loc_consumer_mutex);
171
172 if (loc_consumer_sess == NULL)
173 return NULL;
174
175 return async_exchange_begin(loc_consumer_sess);
176}
177
178/** Finish an async exchange on the loc session.
179 *
180 * @param exch Exchange to be finished.
181 *
182 */
183void loc_exchange_end(async_exch_t *exch)
184{
185 async_exchange_end(exch);
186}
187
188/** Register new server with loc.
189 *
190 * @param name Server name
191 * @param rsrv Place to store new server object on success
192 * @return EOK on succes or an error code
193 */
194errno_t loc_server_register(const char *name, loc_srv_t **rsrv)
195{
196 async_exch_t *exch;
197 loc_srv_t *srv;
198
199 srv = calloc(1, sizeof(loc_srv_t));
200 if (srv == NULL)
201 return ENOMEM;
202
203 srv->sess = service_connect_blocking(SERVICE_LOC,
204 INTERFACE_LOC_SUPPLIER, 0, NULL);
205 if (srv->sess == NULL) {
206 free(srv);
207 return ENOMEM;
208 }
209
210 exch = async_exchange_begin(srv->sess);
211
212 ipc_call_t answer;
213 aid_t req = async_send_2(exch, LOC_SERVER_REGISTER, 0, 0, &answer);
214 errno_t retval = async_data_write_start(exch, name, str_size(name));
215
216 if (retval != EOK) {
217 async_forget(req);
218 async_exchange_end(exch);
219 async_hangup(srv->sess);
220 free(srv);
221 return retval;
222 }
223
224 async_connect_to_me(exch, INTERFACE_ANY, 0, 0);
225
226 /*
227 * First wait for the answer and then end the exchange. The opposite
228 * order is generally wrong because it may lead to a deadlock under
229 * certain circumstances.
230 */
231 async_wait_for(req, &retval);
232 async_exchange_end(exch);
233
234 if (retval != EOK) {
235 async_hangup(srv->sess);
236 free(srv);
237 return retval;
238 }
239
240 *rsrv = srv;
241 return retval;
242}
243
244/** Unregister server from loc.
245 *
246 * Unregister server and free server object.
247 *
248 * @param srv Server object
249 */
250void loc_server_unregister(loc_srv_t *srv)
251{
252 async_hangup(srv->sess);
253 free(srv);
254}
255
256/** Register new service.
257 *
258 * @param srv Server object
259 * @param fqsn Fully qualified service name
260 * @param portid ID of port providing the service
261 * @param sid Service ID of new service
262 *
263 */
264errno_t loc_service_register(loc_srv_t *srv, const char *fqsn,
265 port_id_t portid, service_id_t *sid)
266{
267 async_exch_t *exch = async_exchange_begin(srv->sess);
268 ipc_call_t answer;
269 aid_t req = async_send_1(exch, LOC_SERVICE_REGISTER, portid, &answer);
270 errno_t retval = async_data_write_start(exch, fqsn, str_size(fqsn));
271
272 if (retval != EOK) {
273 async_forget(req);
274 async_exchange_end(exch);
275 return retval;
276 }
277
278 /*
279 * First wait for the answer and then end the exchange. The opposite
280 * order is generally wrong because it may lead to a deadlock under
281 * certain circumstances.
282 */
283 async_wait_for(req, &retval);
284 async_exchange_end(exch);
285
286 if (retval != EOK) {
287 if (sid != NULL)
288 *sid = -1;
289
290 return retval;
291 }
292
293 if (sid != NULL)
294 *sid = (service_id_t) ipc_get_arg1(&answer);
295
296 return retval;
297}
298
299/** Unregister service.
300 *
301 * @param srv Server object
302 * @param sid Service ID
303 */
304errno_t loc_service_unregister(loc_srv_t *srv, service_id_t sid)
305{
306 async_exch_t *exch;
307 errno_t retval;
308
309 exch = async_exchange_begin(srv->sess);
310 retval = async_req_1_0(exch, LOC_SERVICE_UNREGISTER, sid);
311 async_exchange_end(exch);
312
313 return (errno_t)retval;
314}
315
316errno_t loc_service_get_id(const char *fqdn, service_id_t *handle,
317 unsigned int flags)
318{
319 async_exch_t *exch;
320
321 if (flags & IPC_FLAG_BLOCKING)
322 exch = loc_exchange_begin_blocking();
323 else {
324 exch = loc_exchange_begin();
325 if (exch == NULL)
326 return errno;
327 }
328
329 ipc_call_t answer;
330 aid_t req = async_send_2(exch, LOC_SERVICE_GET_ID, flags, 0,
331 &answer);
332 errno_t retval = async_data_write_start(exch, fqdn, str_size(fqdn));
333
334 loc_exchange_end(exch);
335
336 if (retval != EOK) {
337 async_forget(req);
338 return retval;
339 }
340
341 async_wait_for(req, &retval);
342
343 if (retval != EOK) {
344 if (handle != NULL)
345 *handle = (service_id_t) -1;
346
347 return retval;
348 }
349
350 if (handle != NULL)
351 *handle = (service_id_t) ipc_get_arg1(&answer);
352
353 return retval;
354}
355
356/** Get object name.
357 *
358 * Provided ID of an object, return its name.
359 *
360 * @param method IPC method
361 * @param id Object ID
362 * @param name Place to store pointer to new string. Caller should
363 * free it using free().
364 * @return EOK on success or an error code
365 */
366static errno_t loc_get_name_internal(sysarg_t method, sysarg_t id, char **name)
367{
368 async_exch_t *exch;
369 char name_buf[LOC_NAME_MAXLEN + 1];
370 ipc_call_t dreply;
371 size_t act_size;
372 errno_t dretval;
373
374 *name = NULL;
375 exch = loc_exchange_begin_blocking();
376
377 ipc_call_t answer;
378 aid_t req = async_send_1(exch, method, id, &answer);
379 aid_t dreq = async_data_read(exch, name_buf, LOC_NAME_MAXLEN,
380 &dreply);
381 async_wait_for(dreq, &dretval);
382
383 loc_exchange_end(exch);
384
385 if (dretval != EOK) {
386 async_forget(req);
387 return dretval;
388 }
389
390 errno_t retval;
391 async_wait_for(req, &retval);
392
393 if (retval != EOK)
394 return retval;
395
396 act_size = ipc_get_arg2(&dreply);
397 assert(act_size <= LOC_NAME_MAXLEN);
398 name_buf[act_size] = '\0';
399
400 *name = str_dup(name_buf);
401 if (*name == NULL)
402 return ENOMEM;
403
404 return EOK;
405}
406
407/** Get category name.
408 *
409 * Provided ID of a service, return its name.
410 *
411 * @param cat_id Category ID
412 * @param name Place to store pointer to new string. Caller should
413 * free it using free().
414 * @return EOK on success or an error code
415 */
416errno_t loc_category_get_name(category_id_t cat_id, char **name)
417{
418 return loc_get_name_internal(LOC_CATEGORY_GET_NAME, cat_id, name);
419}
420
421/** Get service name.
422 *
423 * Provided ID of a service, return its name.
424 *
425 * @param svc_id Service ID
426 * @param name Place to store pointer to new string. Caller should
427 * free it using free().
428 * @return EOK on success or an error code
429 */
430errno_t loc_service_get_name(service_id_t svc_id, char **name)
431{
432 return loc_get_name_internal(LOC_SERVICE_GET_NAME, svc_id, name);
433}
434
435/** Get service server name.
436 *
437 * Provided ID of a service, return the name of its server.
438 *
439 * @param svc_id Service ID
440 * @param name Place to store pointer to new string. Caller should
441 * free it using free().
442 * @return EOK on success or an error code
443 */
444errno_t loc_service_get_server_name(service_id_t svc_id, char **name)
445{
446 return loc_get_name_internal(LOC_SERVICE_GET_SERVER_NAME, svc_id, name);
447}
448
449errno_t loc_namespace_get_id(const char *name, service_id_t *handle,
450 unsigned int flags)
451{
452 async_exch_t *exch;
453
454 if (flags & IPC_FLAG_BLOCKING)
455 exch = loc_exchange_begin_blocking();
456 else {
457 exch = loc_exchange_begin();
458 if (exch == NULL)
459 return errno;
460 }
461
462 ipc_call_t answer;
463 aid_t req = async_send_2(exch, LOC_NAMESPACE_GET_ID, flags, 0,
464 &answer);
465 errno_t retval = async_data_write_start(exch, name, str_size(name));
466
467 loc_exchange_end(exch);
468
469 if (retval != EOK) {
470 async_forget(req);
471 return retval;
472 }
473
474 async_wait_for(req, &retval);
475
476 if (retval != EOK) {
477 if (handle != NULL)
478 *handle = (service_id_t) -1;
479
480 return retval;
481 }
482
483 if (handle != NULL)
484 *handle = (service_id_t) ipc_get_arg1(&answer);
485
486 return retval;
487}
488
489/** Get category ID.
490 *
491 * Provided name of a category, return its ID.
492 *
493 * @param name Category name
494 * @param cat_id Place to store ID
495 * @param flags IPC_FLAG_BLOCKING to wait for location service to start
496 * @return EOK on success or an error code
497 */
498errno_t loc_category_get_id(const char *name, category_id_t *cat_id,
499 unsigned int flags)
500{
501 async_exch_t *exch;
502
503 if (flags & IPC_FLAG_BLOCKING)
504 exch = loc_exchange_begin_blocking();
505 else {
506 exch = loc_exchange_begin();
507 if (exch == NULL)
508 return errno;
509 }
510
511 ipc_call_t answer;
512 aid_t req = async_send_0(exch, LOC_CATEGORY_GET_ID,
513 &answer);
514 errno_t retval = async_data_write_start(exch, name, str_size(name));
515
516 loc_exchange_end(exch);
517
518 if (retval != EOK) {
519 async_forget(req);
520 return retval;
521 }
522
523 async_wait_for(req, &retval);
524
525 if (retval != EOK) {
526 if (cat_id != NULL)
527 *cat_id = (category_id_t) -1;
528
529 return retval;
530 }
531
532 if (cat_id != NULL)
533 *cat_id = (category_id_t) ipc_get_arg1(&answer);
534
535 return retval;
536}
537
538loc_object_type_t loc_id_probe(service_id_t handle)
539{
540 async_exch_t *exch = loc_exchange_begin_blocking();
541
542 sysarg_t type;
543 errno_t retval = async_req_1_1(exch, LOC_ID_PROBE, handle, &type);
544
545 loc_exchange_end(exch);
546
547 if (retval != EOK)
548 return LOC_OBJECT_NONE;
549
550 return (loc_object_type_t) type;
551}
552
553async_sess_t *loc_service_connect(service_id_t handle, iface_t iface,
554 unsigned int flags)
555{
556 async_sess_t *sess;
557
558 if (flags & IPC_FLAG_BLOCKING)
559 sess = service_connect_blocking(SERVICE_LOC, iface, handle, NULL);
560 else
561 sess = service_connect(SERVICE_LOC, iface, handle, NULL);
562
563 return sess;
564}
565
566/**
567 * @return ID of a new NULL device, or -1 if failed.
568 */
569int loc_null_create(void)
570{
571 async_exch_t *exch = loc_exchange_begin_blocking();
572
573 sysarg_t null_id;
574 errno_t retval = async_req_0_1(exch, LOC_NULL_CREATE, &null_id);
575
576 loc_exchange_end(exch);
577
578 if (retval != EOK)
579 return -1;
580
581 return (int) null_id;
582}
583
584void loc_null_destroy(int null_id)
585{
586 async_exch_t *exch = loc_exchange_begin_blocking();
587 async_req_1_0(exch, LOC_NULL_DESTROY, (sysarg_t) null_id);
588 loc_exchange_end(exch);
589}
590
591static size_t loc_count_namespaces_internal(async_exch_t *exch)
592{
593 sysarg_t count;
594 errno_t retval = async_req_0_1(exch, LOC_GET_NAMESPACE_COUNT, &count);
595 if (retval != EOK)
596 return 0;
597
598 return count;
599}
600
601/** Add service to category.
602 *
603 * @param srv Server object
604 * @param svc_id Service ID
605 * @param cat_id Category ID
606 *
607 * @return EOK on success or an error code
608 */
609errno_t loc_service_add_to_cat(loc_srv_t *srv, service_id_t svc_id,
610 service_id_t cat_id)
611{
612 async_exch_t *exch;
613 errno_t retval;
614
615 exch = async_exchange_begin(srv->sess);
616 retval = async_req_2_0(exch, LOC_SERVICE_ADD_TO_CAT, svc_id, cat_id);
617 async_exchange_end(exch);
618
619 return retval;
620}
621
622static size_t loc_count_services_internal(async_exch_t *exch,
623 service_id_t ns_handle)
624{
625 sysarg_t count;
626 errno_t retval = async_req_1_1(exch, LOC_GET_SERVICE_COUNT, ns_handle,
627 &count);
628 if (retval != EOK)
629 return 0;
630
631 return count;
632}
633
634size_t loc_count_namespaces(void)
635{
636 async_exch_t *exch = loc_exchange_begin_blocking();
637 size_t size = loc_count_namespaces_internal(exch);
638 loc_exchange_end(exch);
639
640 return size;
641}
642
643size_t loc_count_services(service_id_t ns_handle)
644{
645 async_exch_t *exch = loc_exchange_begin_blocking();
646 size_t size = loc_count_services_internal(exch, ns_handle);
647 loc_exchange_end(exch);
648
649 return size;
650}
651
652size_t loc_get_namespaces(loc_sdesc_t **data)
653{
654 /* Loop until read is succesful */
655 while (true) {
656 async_exch_t *exch = loc_exchange_begin_blocking();
657 size_t count = loc_count_namespaces_internal(exch);
658 loc_exchange_end(exch);
659
660 if (count == 0)
661 return 0;
662
663 loc_sdesc_t *devs = (loc_sdesc_t *) calloc(count, sizeof(loc_sdesc_t));
664 if (devs == NULL)
665 return 0;
666
667 exch = loc_exchange_begin();
668
669 ipc_call_t answer;
670 aid_t req = async_send_0(exch, LOC_GET_NAMESPACES, &answer);
671 errno_t rc = async_data_read_start(exch, devs, count * sizeof(loc_sdesc_t));
672
673 loc_exchange_end(exch);
674
675 if (rc == EOVERFLOW) {
676 /*
677 * Number of namespaces has changed since
678 * the last call of LOC_GET_NAMESPACE_COUNT
679 */
680 free(devs);
681 continue;
682 }
683
684 if (rc != EOK) {
685 async_forget(req);
686 free(devs);
687 return 0;
688 }
689
690 errno_t retval;
691 async_wait_for(req, &retval);
692
693 if (retval != EOK)
694 return 0;
695
696 *data = devs;
697 return count;
698 }
699}
700
701size_t loc_get_services(service_id_t ns_handle, loc_sdesc_t **data)
702{
703 /* Loop until read is succesful */
704 while (true) {
705 async_exch_t *exch = loc_exchange_begin_blocking();
706 size_t count = loc_count_services_internal(exch, ns_handle);
707 loc_exchange_end(exch);
708
709 if (count == 0)
710 return 0;
711
712 loc_sdesc_t *devs = (loc_sdesc_t *) calloc(count, sizeof(loc_sdesc_t));
713 if (devs == NULL)
714 return 0;
715
716 exch = loc_exchange_begin();
717
718 ipc_call_t answer;
719 aid_t req = async_send_1(exch, LOC_GET_SERVICES, ns_handle, &answer);
720 errno_t rc = async_data_read_start(exch, devs, count * sizeof(loc_sdesc_t));
721
722 loc_exchange_end(exch);
723
724 if (rc == EOVERFLOW) {
725 /*
726 * Number of services has changed since
727 * the last call of LOC_GET_SERVICE_COUNT
728 */
729 free(devs);
730 continue;
731 }
732
733 if (rc != EOK) {
734 async_forget(req);
735 free(devs);
736 return 0;
737 }
738
739 errno_t retval;
740 async_wait_for(req, &retval);
741
742 if (retval != EOK)
743 return 0;
744
745 *data = devs;
746 return count;
747 }
748}
749
750static errno_t loc_category_get_ids_once(sysarg_t method, sysarg_t arg1,
751 sysarg_t *id_buf, size_t buf_size, size_t *act_size)
752{
753 async_exch_t *exch = loc_exchange_begin_blocking();
754
755 ipc_call_t answer;
756 aid_t req = async_send_1(exch, method, arg1, &answer);
757 errno_t rc = async_data_read_start(exch, id_buf, buf_size);
758
759 loc_exchange_end(exch);
760
761 if (rc != EOK) {
762 async_forget(req);
763 return rc;
764 }
765
766 errno_t retval;
767 async_wait_for(req, &retval);
768
769 if (retval != EOK) {
770 return retval;
771 }
772
773 *act_size = ipc_get_arg1(&answer);
774 return EOK;
775}
776
777/** Get list of IDs.
778 *
779 * Returns an allocated array of service IDs.
780 *
781 * @param method IPC method
782 * @param arg1 IPC argument 1
783 * @param data Place to store pointer to array of IDs
784 * @param count Place to store number of IDs
785 * @return EOK on success or an error code
786 */
787static errno_t loc_get_ids_internal(sysarg_t method, sysarg_t arg1,
788 sysarg_t **data, size_t *count)
789{
790 *data = NULL;
791 *count = 0;
792
793 size_t act_size = 0;
794 errno_t rc = loc_category_get_ids_once(method, arg1, NULL, 0,
795 &act_size);
796 if (rc != EOK)
797 return rc;
798
799 size_t alloc_size = act_size;
800 service_id_t *ids = malloc(alloc_size);
801 if (ids == NULL)
802 return ENOMEM;
803
804 while (true) {
805 rc = loc_category_get_ids_once(method, arg1, ids, alloc_size,
806 &act_size);
807 if (rc != EOK)
808 return rc;
809
810 if (act_size <= alloc_size)
811 break;
812
813 alloc_size = act_size;
814 service_id_t *tmp = realloc(ids, alloc_size);
815 if (tmp == NULL) {
816 free(ids);
817 return ENOMEM;
818 }
819 ids = tmp;
820 }
821
822 *count = act_size / sizeof(category_id_t);
823 *data = ids;
824 return EOK;
825}
826
827/** Get list of services in category.
828 *
829 * Returns an allocated array of service IDs.
830 *
831 * @param cat_id Category ID
832 * @param data Place to store pointer to array of IDs
833 * @param count Place to store number of IDs
834 * @return EOK on success or an error code
835 */
836errno_t loc_category_get_svcs(category_id_t cat_id, service_id_t **data,
837 size_t *count)
838{
839 return loc_get_ids_internal(LOC_CATEGORY_GET_SVCS, cat_id,
840 data, count);
841}
842
843/** Get list of categories.
844 *
845 * Returns an allocated array of category IDs.
846 *
847 * @param data Place to store pointer to array of IDs
848 * @param count Place to store number of IDs
849 * @return EOK on success or an error code
850 */
851errno_t loc_get_categories(category_id_t **data, size_t *count)
852{
853 return loc_get_ids_internal(LOC_GET_CATEGORIES, 0,
854 data, count);
855}
856
857errno_t loc_register_cat_change_cb(loc_cat_change_cb_t cb_fun, void *cb_arg)
858{
859 fibril_mutex_lock(&loc_callback_mutex);
860 if (cat_change_cb != NULL) {
861 fibril_mutex_unlock(&loc_callback_mutex);
862 return EEXIST;
863 }
864
865 if (loc_callback_create() != EOK) {
866 fibril_mutex_unlock(&loc_callback_mutex);
867 return EIO;
868 }
869
870 cat_change_cb = cb_fun;
871 cat_change_arg = cb_arg;
872 fibril_mutex_unlock(&loc_callback_mutex);
873
874 return EOK;
875}
Note: See TracBrowser for help on using the repository browser.