source: mainline/uspace/lib/c/generic/loc.c@ 763e0cd

lfn serial ticket/834-toolchain-update topic/fix-logger-deadlock topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 763e0cd was 763e0cd, checked in by Jiri Svoboda <jiri@…>, 15 years ago

Locinfo utility. Right now displays yellow pages.

  • Property mode set to 100644
File size: 19.5 KB
Line 
1/*
2 * Copyright (c) 2007 Josef Cejka
3 * Copyright (c) 2011 Jiri Svoboda
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 <malloc.h>
39#include <bool.h>
40
41static FIBRIL_MUTEX_INITIALIZE(loc_supp_block_mutex);
42static FIBRIL_MUTEX_INITIALIZE(loc_cons_block_mutex);
43
44static FIBRIL_MUTEX_INITIALIZE(loc_supplier_mutex);
45static FIBRIL_MUTEX_INITIALIZE(loc_consumer_mutex);
46
47static FIBRIL_MUTEX_INITIALIZE(loc_callback_mutex);
48static bool loc_callback_created = false;
49
50static async_sess_t *loc_supp_block_sess = NULL;
51static async_sess_t *loc_cons_block_sess = NULL;
52
53static async_sess_t *loc_supplier_sess = NULL;
54static async_sess_t *loc_consumer_sess = NULL;
55
56static loc_cat_change_cb_t cat_change_cb = NULL;
57
58static void loc_cb_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
59{
60 loc_cat_change_cb_t cb_fun;
61
62 while (true) {
63 ipc_call_t call;
64 ipc_callid_t callid = async_get_call(&call);
65
66 if (!IPC_GET_IMETHOD(call)) {
67 /* TODO: Handle hangup */
68 return;
69 }
70
71 int retval;
72
73 switch (IPC_GET_IMETHOD(call)) {
74 case LOC_EVENT_CAT_CHANGE:
75 fibril_mutex_lock(&loc_callback_mutex);
76 cb_fun = cat_change_cb;
77 if (cb_fun != NULL) {
78 (*cb_fun)();
79 }
80 fibril_mutex_unlock(&loc_callback_mutex);
81 retval = 0;
82 break;
83 default:
84 retval = ENOTSUP;
85 }
86
87 async_answer_0(callid, retval);
88 }
89}
90
91
92static void clone_session(fibril_mutex_t *mtx, async_sess_t *src,
93 async_sess_t **dst)
94{
95 fibril_mutex_lock(mtx);
96
97 if ((*dst == NULL) && (src != NULL))
98 *dst = src;
99
100 fibril_mutex_unlock(mtx);
101}
102
103static int loc_callback_create(void)
104{
105 async_exch_t *exch;
106 sysarg_t retval;
107 int rc = EOK;
108
109 fibril_mutex_lock(&loc_callback_mutex);
110
111 if (!loc_callback_created) {
112 exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
113
114 ipc_call_t answer;
115 aid_t req = async_send_0(exch, LOC_CALLBACK_CREATE, &answer);
116 async_connect_to_me(exch, 0, 0, 0, loc_cb_conn, NULL);
117 loc_exchange_end(exch);
118
119 async_wait_for(req, &retval);
120 if (rc != EOK)
121 goto done;
122
123 if (retval != EOK) {
124 rc = retval;
125 goto done;
126 }
127
128 loc_callback_created = true;
129 }
130
131 rc = EOK;
132done:
133 fibril_mutex_unlock(&loc_callback_mutex);
134 return rc;
135}
136
137/** Start an async exchange on the loc session (blocking).
138 *
139 * @param iface Location service interface to choose
140 *
141 * @return New exchange.
142 *
143 */
144async_exch_t *loc_exchange_begin_blocking(loc_interface_t iface)
145{
146 switch (iface) {
147 case LOC_PORT_SUPPLIER:
148 fibril_mutex_lock(&loc_supp_block_mutex);
149
150 while (loc_supp_block_sess == NULL) {
151 clone_session(&loc_supplier_mutex, loc_supplier_sess,
152 &loc_supp_block_sess);
153
154 if (loc_supp_block_sess == NULL)
155 loc_supp_block_sess =
156 service_connect_blocking(EXCHANGE_SERIALIZE,
157 SERVICE_LOC, LOC_PORT_SUPPLIER, 0);
158 }
159
160 fibril_mutex_unlock(&loc_supp_block_mutex);
161
162 clone_session(&loc_supplier_mutex, loc_supp_block_sess,
163 &loc_supplier_sess);
164
165 return async_exchange_begin(loc_supp_block_sess);
166 case LOC_PORT_CONSUMER:
167 fibril_mutex_lock(&loc_cons_block_mutex);
168
169 while (loc_cons_block_sess == NULL) {
170 clone_session(&loc_consumer_mutex, loc_consumer_sess,
171 &loc_cons_block_sess);
172
173 if (loc_cons_block_sess == NULL)
174 loc_cons_block_sess =
175 service_connect_blocking(EXCHANGE_SERIALIZE,
176 SERVICE_LOC, LOC_PORT_CONSUMER, 0);
177 }
178
179 fibril_mutex_unlock(&loc_cons_block_mutex);
180
181 clone_session(&loc_consumer_mutex, loc_cons_block_sess,
182 &loc_consumer_sess);
183
184 return async_exchange_begin(loc_cons_block_sess);
185 default:
186 return NULL;
187 }
188}
189
190/** Start an async exchange on the loc session.
191 *
192 * @param iface Location service interface to choose
193 *
194 * @return New exchange.
195 *
196 */
197async_exch_t *loc_exchange_begin(loc_interface_t iface)
198{
199 switch (iface) {
200 case LOC_PORT_SUPPLIER:
201 fibril_mutex_lock(&loc_supplier_mutex);
202
203 if (loc_supplier_sess == NULL)
204 loc_supplier_sess =
205 service_connect(EXCHANGE_SERIALIZE, SERVICE_LOC,
206 LOC_PORT_SUPPLIER, 0);
207
208 fibril_mutex_unlock(&loc_supplier_mutex);
209
210 if (loc_supplier_sess == NULL)
211 return NULL;
212
213 return async_exchange_begin(loc_supplier_sess);
214 case LOC_PORT_CONSUMER:
215 fibril_mutex_lock(&loc_consumer_mutex);
216
217 if (loc_consumer_sess == NULL)
218 loc_consumer_sess =
219 service_connect(EXCHANGE_SERIALIZE, SERVICE_LOC,
220 LOC_PORT_CONSUMER, 0);
221
222 fibril_mutex_unlock(&loc_consumer_mutex);
223
224 if (loc_consumer_sess == NULL)
225 return NULL;
226
227 return async_exchange_begin(loc_consumer_sess);
228 default:
229 return NULL;
230 }
231}
232
233/** Finish an async exchange on the loc session.
234 *
235 * @param exch Exchange to be finished.
236 *
237 */
238void loc_exchange_end(async_exch_t *exch)
239{
240 async_exchange_end(exch);
241}
242
243/** Register new driver with loc. */
244int loc_server_register(const char *name, async_client_conn_t conn)
245{
246 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_SUPPLIER);
247
248 ipc_call_t answer;
249 aid_t req = async_send_2(exch, LOC_SERVER_REGISTER, 0, 0, &answer);
250 sysarg_t retval = async_data_write_start(exch, name, str_size(name));
251
252 loc_exchange_end(exch);
253
254 if (retval != EOK) {
255 async_wait_for(req, NULL);
256 return retval;
257 }
258
259 async_set_client_connection(conn);
260
261 exch = loc_exchange_begin(LOC_PORT_SUPPLIER);
262 async_connect_to_me(exch, 0, 0, 0, NULL, NULL);
263 loc_exchange_end(exch);
264
265 async_wait_for(req, &retval);
266 return retval;
267}
268
269/** Register new device.
270 *
271 * The @p interface is used when forwarding connection to the driver.
272 * If not 0, the first argument is the interface and the second argument
273 * is the service ID.
274 *
275 * When the interface is zero (default), the first argument is directly
276 * the handle (to ensure backward compatibility).
277 *
278 * @param fqdn Fully qualified device name.
279 * @param[out] handle Handle to the created instance of device.
280 * @param interface Interface when forwarding.
281 *
282 */
283int loc_service_register_with_iface(const char *fqdn,
284 service_id_t *handle, sysarg_t interface)
285{
286 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_SUPPLIER);
287
288 ipc_call_t answer;
289 aid_t req = async_send_2(exch, LOC_SERVICE_REGISTER, interface, 0,
290 &answer);
291 sysarg_t retval = async_data_write_start(exch, fqdn, str_size(fqdn));
292
293 loc_exchange_end(exch);
294
295 if (retval != EOK) {
296 async_wait_for(req, NULL);
297 return retval;
298 }
299
300 async_wait_for(req, &retval);
301
302 if (retval != EOK) {
303 if (handle != NULL)
304 *handle = -1;
305
306 return retval;
307 }
308
309 if (handle != NULL)
310 *handle = (service_id_t) IPC_GET_ARG1(answer);
311
312 return retval;
313}
314
315/** Register new device.
316 *
317 * @param fqdn Fully qualified device name.
318 * @param handle Output: Handle to the created instance of device.
319 *
320 */
321int loc_service_register(const char *fqdn, service_id_t *handle)
322{
323 return loc_service_register_with_iface(fqdn, handle, 0);
324}
325
326int loc_service_get_id(const char *fqdn, service_id_t *handle,
327 unsigned int flags)
328{
329 async_exch_t *exch;
330
331 if (flags & IPC_FLAG_BLOCKING)
332 exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
333 else {
334 exch = loc_exchange_begin(LOC_PORT_CONSUMER);
335 if (exch == NULL)
336 return errno;
337 }
338
339 ipc_call_t answer;
340 aid_t req = async_send_2(exch, LOC_SERVICE_GET_ID, flags, 0,
341 &answer);
342 sysarg_t retval = async_data_write_start(exch, fqdn, str_size(fqdn));
343
344 loc_exchange_end(exch);
345
346 if (retval != EOK) {
347 async_wait_for(req, NULL);
348 return retval;
349 }
350
351 async_wait_for(req, &retval);
352
353 if (retval != EOK) {
354 if (handle != NULL)
355 *handle = (service_id_t) -1;
356
357 return retval;
358 }
359
360 if (handle != NULL)
361 *handle = (service_id_t) IPC_GET_ARG1(answer);
362
363 return retval;
364}
365
366/** Get object name.
367 *
368 * Provided ID of an object, return its name.
369 *
370 * @param method IPC method
371 * @param id Object ID
372 * @param name Place to store pointer to new string. Caller should
373 * free it using free().
374 * @return EOK on success or negative error code
375 */
376static int loc_get_name_internal(sysarg_t method, sysarg_t id, char **name)
377{
378 async_exch_t *exch;
379 char name_buf[LOC_NAME_MAXLEN + 1];
380 ipc_call_t dreply;
381 size_t act_size;
382 sysarg_t dretval;
383
384 *name = NULL;
385 exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
386
387 ipc_call_t answer;
388 aid_t req = async_send_1(exch, method, id, &answer);
389 aid_t dreq = async_data_read(exch, name_buf, LOC_NAME_MAXLEN,
390 &dreply);
391 async_wait_for(dreq, &dretval);
392
393 loc_exchange_end(exch);
394
395 if (dretval != EOK) {
396 async_wait_for(req, NULL);
397 return dretval;
398 }
399
400 sysarg_t retval;
401 async_wait_for(req, &retval);
402
403 if (retval != EOK)
404 return retval;
405
406 act_size = IPC_GET_ARG2(dreply);
407 assert(act_size <= LOC_NAME_MAXLEN);
408 name_buf[act_size] = '\0';
409
410 *name = str_dup(name_buf);
411 if (*name == NULL)
412 return ENOMEM;
413
414 return EOK;
415}
416
417/** Get category name.
418 *
419 * Provided ID of a service, return its name.
420 *
421 * @param cat_id Category ID
422 * @param name Place to store pointer to new string. Caller should
423 * free it using free().
424 * @return EOK on success or negative error code
425 */
426int loc_category_get_name(category_id_t cat_id, char **name)
427{
428 return loc_get_name_internal(LOC_CATEGORY_GET_NAME, cat_id, name);
429}
430
431/** Get service name.
432 *
433 * Provided ID of a service, return its name.
434 *
435 * @param svc_id Service ID
436 * @param name Place to store pointer to new string. Caller should
437 * free it using free().
438 * @return EOK on success or negative error code
439 */
440int loc_service_get_name(service_id_t svc_id, char **name)
441{
442 return loc_get_name_internal(LOC_SERVICE_GET_NAME, svc_id, name);
443}
444
445int loc_namespace_get_id(const char *name, service_id_t *handle,
446 unsigned int flags)
447{
448 async_exch_t *exch;
449
450 if (flags & IPC_FLAG_BLOCKING)
451 exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
452 else {
453 exch = loc_exchange_begin(LOC_PORT_CONSUMER);
454 if (exch == NULL)
455 return errno;
456 }
457
458 ipc_call_t answer;
459 aid_t req = async_send_2(exch, LOC_NAMESPACE_GET_ID, flags, 0,
460 &answer);
461 sysarg_t retval = async_data_write_start(exch, name, str_size(name));
462
463 loc_exchange_end(exch);
464
465 if (retval != EOK) {
466 async_wait_for(req, NULL);
467 return retval;
468 }
469
470 async_wait_for(req, &retval);
471
472 if (retval != EOK) {
473 if (handle != NULL)
474 *handle = (service_id_t) -1;
475
476 return retval;
477 }
478
479 if (handle != NULL)
480 *handle = (service_id_t) IPC_GET_ARG1(answer);
481
482 return retval;
483}
484
485/** Get category ID.
486 *
487 * Provided name of a category, return its ID.
488 *
489 * @param name Category name
490 * @param cat_id Place to store ID
491 * @param flags IPC_FLAG_BLOCKING to wait for location service to start
492 * @return EOK on success or negative error code
493 */
494int loc_category_get_id(const char *name, category_id_t *cat_id,
495 unsigned int flags)
496{
497 async_exch_t *exch;
498
499 if (flags & IPC_FLAG_BLOCKING)
500 exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
501 else {
502 exch = loc_exchange_begin(LOC_PORT_CONSUMER);
503 if (exch == NULL)
504 return errno;
505 }
506
507 ipc_call_t answer;
508 aid_t req = async_send_0(exch, LOC_CATEGORY_GET_ID,
509 &answer);
510 sysarg_t retval = async_data_write_start(exch, name, str_size(name));
511
512 loc_exchange_end(exch);
513
514 if (retval != EOK) {
515 async_wait_for(req, NULL);
516 return retval;
517 }
518
519 async_wait_for(req, &retval);
520
521 if (retval != EOK) {
522 if (cat_id != NULL)
523 *cat_id = (category_id_t) -1;
524
525 return retval;
526 }
527
528 if (cat_id != NULL)
529 *cat_id = (category_id_t) IPC_GET_ARG1(answer);
530
531 return retval;
532}
533
534
535loc_object_type_t loc_id_probe(service_id_t handle)
536{
537 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
538
539 sysarg_t type;
540 int retval = async_req_1_1(exch, LOC_ID_PROBE, handle, &type);
541
542 loc_exchange_end(exch);
543
544 if (retval != EOK)
545 return LOC_OBJECT_NONE;
546
547 return (loc_object_type_t) type;
548}
549
550async_sess_t *loc_service_connect(exch_mgmt_t mgmt, service_id_t handle,
551 unsigned int flags)
552{
553 async_sess_t *sess;
554
555 if (flags & IPC_FLAG_BLOCKING)
556 sess = service_connect_blocking(mgmt, SERVICE_LOC,
557 LOC_CONNECT_TO_SERVICE, handle);
558 else
559 sess = service_connect(mgmt, SERVICE_LOC,
560 LOC_CONNECT_TO_SERVICE, handle);
561
562 return sess;
563}
564
565int loc_null_create(void)
566{
567 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
568
569 sysarg_t null_id;
570 int retval = async_req_0_1(exch, LOC_NULL_CREATE, &null_id);
571
572 loc_exchange_end(exch);
573
574 if (retval != EOK)
575 return -1;
576
577 return (int) null_id;
578}
579
580void loc_null_destroy(int null_id)
581{
582 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
583 async_req_1_0(exch, LOC_NULL_DESTROY, (sysarg_t) null_id);
584 loc_exchange_end(exch);
585}
586
587static size_t loc_count_namespaces_internal(async_exch_t *exch)
588{
589 sysarg_t count;
590 int retval = async_req_0_1(exch, LOC_GET_NAMESPACE_COUNT, &count);
591 if (retval != EOK)
592 return 0;
593
594 return count;
595}
596
597/** Add service to category.
598 *
599 * @param svc_id Service ID
600 * @param cat_id Category ID
601 * @return EOK on success or negative error code
602 */
603int loc_service_add_to_cat(service_id_t svc_id, service_id_t cat_id)
604{
605 async_exch_t *exch;
606 sysarg_t retval;
607
608 exch = loc_exchange_begin_blocking(LOC_PORT_SUPPLIER);
609 retval = async_req_2_0(exch, LOC_SERVICE_ADD_TO_CAT, svc_id, cat_id);
610 loc_exchange_end(exch);
611
612 return retval;
613}
614
615static size_t loc_count_services_internal(async_exch_t *exch,
616 service_id_t ns_handle)
617{
618 sysarg_t count;
619 int retval = async_req_1_1(exch, LOC_GET_SERVICE_COUNT, ns_handle,
620 &count);
621 if (retval != EOK)
622 return 0;
623
624 return count;
625}
626
627size_t loc_count_namespaces(void)
628{
629 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
630 size_t size = loc_count_namespaces_internal(exch);
631 loc_exchange_end(exch);
632
633 return size;
634}
635
636size_t loc_count_services(service_id_t ns_handle)
637{
638 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
639 size_t size = loc_count_services_internal(exch, ns_handle);
640 loc_exchange_end(exch);
641
642 return size;
643}
644
645size_t loc_get_namespaces(loc_sdesc_t **data)
646{
647 /* Loop until read is succesful */
648 while (true) {
649 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
650 size_t count = loc_count_namespaces_internal(exch);
651 loc_exchange_end(exch);
652
653 if (count == 0)
654 return 0;
655
656 loc_sdesc_t *devs = (loc_sdesc_t *) calloc(count, sizeof(loc_sdesc_t));
657 if (devs == NULL)
658 return 0;
659
660 exch = loc_exchange_begin(LOC_PORT_CONSUMER);
661
662 ipc_call_t answer;
663 aid_t req = async_send_0(exch, LOC_GET_NAMESPACES, &answer);
664 int rc = async_data_read_start(exch, devs, count * sizeof(loc_sdesc_t));
665
666 loc_exchange_end(exch);
667
668 if (rc == EOVERFLOW) {
669 /*
670 * Number of namespaces has changed since
671 * the last call of LOC_GET_NAMESPACE_COUNT
672 */
673 free(devs);
674 continue;
675 }
676
677 if (rc != EOK) {
678 async_wait_for(req, NULL);
679 free(devs);
680 return 0;
681 }
682
683 sysarg_t retval;
684 async_wait_for(req, &retval);
685
686 if (retval != EOK)
687 return 0;
688
689 *data = devs;
690 return count;
691 }
692}
693
694size_t loc_get_services(service_id_t ns_handle, loc_sdesc_t **data)
695{
696 /* Loop until read is succesful */
697 while (true) {
698 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
699 size_t count = loc_count_services_internal(exch, ns_handle);
700 loc_exchange_end(exch);
701
702 if (count == 0)
703 return 0;
704
705 loc_sdesc_t *devs = (loc_sdesc_t *) calloc(count, sizeof(loc_sdesc_t));
706 if (devs == NULL)
707 return 0;
708
709 exch = loc_exchange_begin(LOC_PORT_CONSUMER);
710
711 ipc_call_t answer;
712 aid_t req = async_send_1(exch, LOC_GET_SERVICES, ns_handle, &answer);
713 int rc = async_data_read_start(exch, devs, count * sizeof(loc_sdesc_t));
714
715 loc_exchange_end(exch);
716
717 if (rc == EOVERFLOW) {
718 /*
719 * Number of services has changed since
720 * the last call of LOC_GET_SERVICE_COUNT
721 */
722 free(devs);
723 continue;
724 }
725
726 if (rc != EOK) {
727 async_wait_for(req, NULL);
728 free(devs);
729 return 0;
730 }
731
732 sysarg_t retval;
733 async_wait_for(req, &retval);
734
735 if (retval != EOK)
736 return 0;
737
738 *data = devs;
739 return count;
740 }
741}
742
743static int loc_category_get_ids_once(sysarg_t method, sysarg_t arg1,
744 sysarg_t *id_buf, size_t buf_size, size_t *act_size)
745{
746 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
747
748 ipc_call_t answer;
749 aid_t req = async_send_1(exch, method, arg1, &answer);
750 int rc = async_data_read_start(exch, id_buf, buf_size);
751
752 loc_exchange_end(exch);
753
754 if (rc != EOK) {
755 async_wait_for(req, NULL);
756 return rc;
757 }
758
759 sysarg_t retval;
760 async_wait_for(req, &retval);
761
762 if (retval != EOK) {
763 return retval;
764 }
765
766 *act_size = IPC_GET_ARG1(answer);
767 return EOK;
768}
769
770/** Get list of IDs.
771 *
772 * Returns an allocated array of service IDs.
773 *
774 * @param method IPC method
775 * @param arg1 IPC argument 1
776 * @param data Place to store pointer to array of IDs
777 * @param count Place to store number of IDs
778 * @return EOK on success or negative error code
779 */
780static int loc_get_ids_internal(sysarg_t method, sysarg_t arg1,
781 sysarg_t **data, size_t *count)
782{
783 service_id_t *ids;
784 size_t act_size;
785 size_t alloc_size;
786 int rc;
787
788 *data = NULL;
789 act_size = 0; /* silence warning */
790
791 rc = loc_category_get_ids_once(method, arg1, NULL, 0,
792 &act_size);
793 if (rc != EOK)
794 return rc;
795
796 alloc_size = act_size;
797 ids = malloc(alloc_size);
798 if (ids == NULL)
799 return ENOMEM;
800
801 while (true) {
802 rc = loc_category_get_ids_once(method, arg1, ids, alloc_size,
803 &act_size);
804 if (rc != EOK)
805 return rc;
806
807 if (act_size <= alloc_size)
808 break;
809
810 alloc_size *= 2;
811 free(ids);
812
813 ids = malloc(alloc_size);
814 if (ids == NULL)
815 return ENOMEM;
816 }
817
818 *count = act_size / sizeof(category_id_t);
819 *data = ids;
820 return EOK;
821}
822
823/** Get list of services in category.
824 *
825 * Returns an allocated array of service IDs.
826 *
827 * @param cat_id Category ID
828 * @param data Place to store pointer to array of IDs
829 * @param count Place to store number of IDs
830 * @return EOK on success or negative error code
831 */
832int loc_category_get_svcs(category_id_t cat_id, service_id_t **data,
833 size_t *count)
834{
835 return loc_get_ids_internal(LOC_CATEGORY_GET_SVCS, cat_id,
836 data, count);
837}
838
839/** Get list of categories.
840 *
841 * Returns an allocated array of category IDs.
842 *
843 * @param data Place to store pointer to array of IDs
844 * @param count Place to store number of IDs
845 * @return EOK on success or negative error code
846 */
847int loc_get_categories(category_id_t **data, size_t *count)
848{
849 return loc_get_ids_internal(LOC_GET_CATEGORIES, 0,
850 data, count);
851}
852
853int loc_register_cat_change_cb(loc_cat_change_cb_t cb_fun)
854{
855 if (loc_callback_create() != EOK)
856 return EIO;
857
858 cat_change_cb = cb_fun;
859 return EOK;
860}
Note: See TracBrowser for help on using the repository browser.