]> git.saurik.com Git - apple/libinfo.git/blob - lookup.subproj/search_module.c
Libinfo-392.tar.gz
[apple/libinfo.git] / lookup.subproj / search_module.c
1 /*
2 * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <stdlib.h>
25 #include <paths.h>
26 #include <stdarg.h>
27 #include <unistd.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <netdb.h>
32 #include <pthread.h>
33 #include <sys/param.h>
34 #include <sys/stat.h>
35 #include <arpa/inet.h>
36 #include <dispatch/dispatch.h>
37 #include "si_module.h"
38
39 #define _PATH_SI_CONF "/etc/sysinfo.conf"
40
41 #define SEARCH_FLAG_CACHE_ENABLED 0x00000001
42 #define SEARCH_MODULE_FLAG_DISABLED 0x00000001
43
44 typedef struct
45 {
46 si_mod_t **module;
47 uint32_t *module_flags;
48 uint32_t count;
49 uint32_t flags;
50 } search_list_t;
51
52 typedef struct
53 {
54 search_list_t search_list[CATEGORY_COUNT];
55 si_mod_t *cache;
56 } search_si_private_t;
57
58 extern void si_cache_add_item(si_mod_t *si, si_mod_t *src, si_item_t *item);
59 extern void si_cache_add_list(si_mod_t *si, si_mod_t *src, si_list_t *list);
60
61 extern char **_fsi_tokenize(char *data, const char *sep, int trailing_empty, int *ntokens);
62 extern char *_fsi_get_line(FILE *fp);
63
64 static void si_module_config_parse_line(search_si_private_t *pp, char *line);
65 static void si_module_config_modules_for_category(search_si_private_t *pp, int cat, int ntokens, const char * const *tokens);
66
67 static si_mod_t *
68 search_get_module(search_si_private_t *pp, int cat, int *n)
69 {
70 int x;
71
72 if ((pp == NULL) || (n == NULL)) return NULL;
73
74 x = *n;
75 *n = x + 1;
76
77 /* Use custom search list if available */
78 if (pp->search_list[cat].count > 0 && x < pp->search_list[cat].count)
79 {
80 return pp->search_list[cat].module[x];
81 }
82
83 /* Otherwise use the default search list */
84 while (x < pp->search_list[CATEGORY_DEFAULT].count)
85 {
86 if (pp->search_list[CATEGORY_DEFAULT].module_flags[x] & SEARCH_MODULE_FLAG_DISABLED)
87 {
88 x++;
89 *n = x + 1;
90 }
91 else
92 {
93 return pp->search_list[CATEGORY_DEFAULT].module[x];
94 }
95 }
96
97 return NULL;
98 }
99
100 __private_extern__ void
101 search_set_flags(si_mod_t *si, const char *name, uint32_t flag)
102 {
103 search_si_private_t *pp;
104 uint32_t i;
105
106 if (si == NULL) return;
107 if (si->private == NULL) return;
108
109 pp = (search_si_private_t *)si->private;
110
111 for (i = 0; i < pp->search_list[CATEGORY_DEFAULT].count; i++)
112 {
113 si_mod_t *mod = pp->search_list[CATEGORY_DEFAULT].module[i];
114 if ((mod == NULL) || (mod->name == NULL)) continue;
115
116 if (string_equal(name, mod->name))
117 {
118 pp->search_list[CATEGORY_DEFAULT].module_flags[i] = flag;
119 break;
120 }
121 }
122 }
123
124 static si_mod_t *
125 search_cat_cache(search_si_private_t *pp, int cat)
126 {
127 if (pp == NULL) return NULL;
128 if (cat < 0 || cat > CATEGORY_COUNT) return NULL;
129
130 if (pp->search_list[cat].count == 0)
131 {
132 cat = CATEGORY_DEFAULT;
133 }
134
135 if ((pp->search_list[cat].flags & SEARCH_FLAG_CACHE_ENABLED) != 0)
136 {
137 return pp->cache;
138 }
139
140 return NULL;
141 }
142
143 static void
144 search_close(si_mod_t *si)
145 {
146 int i;
147 search_si_private_t *pp;
148
149 if (si == NULL) return;
150 if (si->private == NULL) return;
151
152 pp = (search_si_private_t *)si->private;
153
154 for (i = 0; i < CATEGORY_COUNT; i++)
155 {
156 if (pp->search_list[i].module != NULL)
157 {
158 free(pp->search_list[i].module);
159 pp->search_list[i].module = NULL;
160 pp->search_list[i].count = 0;
161 pp->search_list[i].flags = 0;
162 }
163 }
164
165 free(pp);
166 }
167
168 static si_item_t *
169 search_item_byname(si_mod_t *si, const char *name, int cat, si_item_t *(*call)(si_mod_t *, const char *))
170 {
171 int i;
172 search_si_private_t *pp;
173 si_item_t *item;
174 si_mod_t *src;
175
176 if (si == NULL) return NULL;
177 if (call == NULL) return NULL;
178
179 pp = (search_si_private_t *)si->private;
180 if (pp == NULL) return NULL;
181
182 i = 0;
183
184 while (NULL != (src = search_get_module(pp, cat, &i)))
185 {
186 item = call(src, name);
187 if (item != NULL)
188 {
189 si_cache_add_item(search_cat_cache(pp, cat), src, item);
190 return item;
191 }
192 }
193
194 return NULL;
195 }
196
197 static si_item_t *
198 search_item_bynumber(si_mod_t *si, uint32_t number, int cat, si_item_t *(*call)(si_mod_t *, uint32_t))
199 {
200 int i;
201 search_si_private_t *pp;
202 si_item_t *item;
203 si_mod_t *src;
204
205 if (si == NULL) return NULL;
206 if (call == NULL) return NULL;
207
208 pp = (search_si_private_t *)si->private;
209 if (pp == NULL) return NULL;
210
211 i = 0;
212
213 while (NULL != (src = search_get_module(pp, cat, &i)))
214 {
215 item = call(src, number);
216 if (item != NULL)
217 {
218 si_cache_add_item(search_cat_cache(pp, cat), src, item);
219 return item;
220 }
221 }
222
223 return NULL;
224 }
225
226 static si_list_t *
227 search_list(si_mod_t *si, int cat, si_list_t *(*call)(si_mod_t *))
228 {
229 int i, null_res;
230 search_si_private_t *pp;
231 si_list_t *list, *all;
232 si_mod_t *cache, *src;
233
234 if (si == NULL) return NULL;
235 if (call == NULL) return NULL;
236
237 pp = (search_si_private_t *)si->private;
238 if (pp == NULL) return NULL;
239
240 cache = search_cat_cache(pp, cat);
241 if (cache != NULL)
242 {
243 list = call(cache);
244 if (list != NULL) return list;
245 }
246
247 i = 0;
248
249 all = NULL;
250 null_res = 0;
251
252 while (NULL != (src = search_get_module(pp, cat, &i)))
253 {
254 if (src == pp->cache) continue;
255
256 list = call(src);
257 if (list == NULL)
258 {
259 null_res = 1;
260 continue;
261 }
262
263 all = si_list_concat(all, list);
264 si_list_release(list);
265 }
266
267 if ((all != NULL) && (null_res == 0)) si_cache_add_list(cache, si, all);
268 return all;
269 }
270
271 static si_item_t *
272 search_user_byname(si_mod_t *si, const char *name)
273 {
274 return search_item_byname(si, name, CATEGORY_USER, si_user_byname);
275 }
276
277 static si_item_t *
278 search_user_byuid(si_mod_t *si, uid_t uid)
279 {
280 return search_item_bynumber(si, (uint32_t)uid, CATEGORY_USER, si_user_byuid);
281 }
282
283 static si_list_t *
284 search_user_all(si_mod_t *si)
285 {
286 return search_list(si, CATEGORY_USER, si_user_all);
287 }
288
289 static si_item_t *
290 search_group_byname(si_mod_t *si, const char *name)
291 {
292 return search_item_byname(si, name, CATEGORY_GROUP, si_group_byname);
293 }
294
295 static si_item_t *
296 search_group_bygid(si_mod_t *si, gid_t gid)
297 {
298 return search_item_bynumber(si, (uint32_t)gid, CATEGORY_USER, si_group_bygid);
299 }
300
301 static si_list_t *
302 search_group_all(si_mod_t *si)
303 {
304 return search_list(si, CATEGORY_GROUP, si_group_all);
305 }
306
307 static si_item_t *
308 search_groupist(si_mod_t *si, const char *name)
309 {
310 return search_item_byname(si, name, CATEGORY_GROUPLIST, si_grouplist);
311 }
312
313 static si_list_t *
314 search_netgroup_byname(si_mod_t *si, const char *name)
315 {
316 int i, cat, null_res;
317 search_si_private_t *pp;
318 si_list_t *list, *all;
319 si_mod_t *cache, *src;
320
321 if (si == NULL) return NULL;
322
323 pp = (search_si_private_t *)si->private;
324 if (pp == NULL) return NULL;
325
326 cat = CATEGORY_NETGROUP;
327
328 cache = search_cat_cache(pp, cat);
329 if (cache != NULL)
330 {
331 list = si_netgroup_byname(cache, name);
332 if (list != NULL) return list;
333 }
334
335 i = 0;
336
337 all = NULL;
338 while (NULL != (src = search_get_module(pp, cat, &i)))
339 {
340 if (src == pp->cache) continue;
341
342 list = si_netgroup_byname(src, name);
343 if (list == NULL)
344 {
345 null_res = 1;
346 continue;
347 }
348
349 all = si_list_concat(all, list);
350 si_list_release(list);
351 }
352
353 if ((all != NULL) && (null_res == 0)) si_cache_add_list(cache, si, all);
354 return all;
355 }
356
357 static int
358 search_in_netgroup(si_mod_t *si, const char *group, const char *host, const char *user, const char *domain)
359 {
360 int i, cat, innetgr;
361 search_si_private_t *pp;
362 si_mod_t *src;
363
364 if (si == NULL) return 0;
365
366 pp = (search_si_private_t *)si->private;
367 if (pp == NULL) return 0;
368
369 cat = CATEGORY_NETGROUP;
370 i = 0;
371 innetgr = 0;
372
373 while (NULL != (src = search_get_module(pp, cat, &i)))
374 {
375 innetgr = si_in_netgroup(src, group, host, user, domain);
376 if (innetgr != 0) return 1;
377 }
378
379 return 0;
380 }
381
382 static si_item_t *
383 search_alias_byname(si_mod_t *si, const char *name)
384 {
385 return search_item_byname(si, name, CATEGORY_ALIAS, si_alias_byname);
386 }
387
388 static si_list_t *
389 search_alias_all(si_mod_t *si)
390 {
391 return search_list(si, CATEGORY_ALIAS, si_alias_all);
392 }
393
394 static si_item_t *
395 search_host_byname(si_mod_t *si, const char *name, int af, const char *interface, uint32_t *err)
396 {
397 int i, cat;
398 search_si_private_t *pp;
399 si_item_t *item;
400 si_mod_t *src;
401
402 if (err != NULL) *err = SI_STATUS_NO_ERROR;
403
404 if ((si == NULL) || (name == NULL))
405 {
406 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
407 return NULL;
408 }
409
410 pp = (search_si_private_t *)si->private;
411 if (pp == NULL)
412 {
413 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
414 return NULL;
415 }
416
417 cat = CATEGORY_HOST_IPV4;
418 if (af == AF_INET6) cat = CATEGORY_HOST_IPV6;
419
420 i = 0;
421
422 while (NULL != (src = search_get_module(pp, cat, &i)))
423 {
424 item = si_host_byname(src, name, af, interface, err);
425 if (item != NULL)
426 {
427 si_cache_add_item(search_cat_cache(pp, cat), src, item);
428 return item;
429 }
430 }
431
432 if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
433 return NULL;
434 }
435
436 static si_item_t *
437 search_host_byaddr(si_mod_t *si, const void *addr, int af, const char *interface, uint32_t *err)
438 {
439 int i, cat;
440 search_si_private_t *pp;
441 si_item_t *item;
442 si_mod_t *src;
443
444 if (err != NULL) *err = SI_STATUS_NO_ERROR;
445
446 if ((si == NULL) || (addr == NULL))
447 {
448 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
449 return NULL;
450 }
451
452 pp = (search_si_private_t *)si->private;
453 if (pp == NULL)
454 {
455 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
456 return NULL;
457 }
458
459 cat = CATEGORY_HOST_IPV4;
460 if (af == AF_INET6) cat = CATEGORY_HOST_IPV6;
461
462 i = 0;
463
464 while (NULL != (src = search_get_module(pp, cat, &i)))
465 {
466 item = si_host_byaddr(src, addr, af, interface, err);
467 if (item != NULL)
468 {
469 si_cache_add_item(search_cat_cache(pp, cat), src, item);
470 return item;
471 }
472 }
473
474 if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
475 return NULL;
476 }
477
478 static si_list_t *
479 search_host_all(si_mod_t *si)
480 {
481 return search_list(si, CATEGORY_HOST, si_host_all);
482 }
483
484 static si_item_t *
485 search_network_byname(si_mod_t *si, const char *name)
486 {
487 return search_item_byname(si, name, CATEGORY_NETWORK, si_network_byname);
488 }
489
490 static si_item_t *
491 search_network_byaddr(si_mod_t *si, uint32_t addr)
492 {
493 return search_item_bynumber(si, addr, CATEGORY_NETWORK, si_network_byaddr);
494 }
495
496 static si_list_t *
497 search_network_all(si_mod_t *si)
498 {
499 return search_list(si, CATEGORY_NETWORK, si_network_all);
500 }
501
502 static si_item_t *
503 search_service_byname(si_mod_t *si, const char *name, const char *proto)
504 {
505 int i, cat;
506 si_item_t *item;
507 search_si_private_t *pp;
508 si_mod_t *src;
509
510 if (si == NULL) return NULL;
511 if (name == NULL) return NULL;
512
513 pp = (search_si_private_t *)si->private;
514 if (pp == NULL) return NULL;
515
516 cat = CATEGORY_SERVICE;
517 i = 0;
518
519 while (NULL != (src = search_get_module(pp, cat, &i)))
520 {
521 item = si_service_byname(src, name, proto);
522 if (item != NULL)
523 {
524 si_cache_add_item(search_cat_cache(pp, cat), src, item);
525 return item;
526 }
527 }
528
529 return NULL;
530 }
531
532 static si_item_t *
533 search_service_byport(si_mod_t *si, int port, const char *proto)
534 {
535 int i, cat;
536 search_si_private_t *pp;
537 si_item_t *item;
538 si_mod_t *src;
539
540 if (si == NULL) return NULL;
541
542 pp = (search_si_private_t *)si->private;
543 if (pp == NULL) return NULL;
544
545 cat = CATEGORY_SERVICE;
546 i = 0;
547
548 while (NULL != (src = search_get_module(pp, cat, &i)))
549 {
550 item = si_service_byport(src, port, proto);
551 if (item != NULL)
552 {
553 si_cache_add_item(search_cat_cache(pp, cat), src, item);
554 return item;
555 }
556 }
557
558 return NULL;
559 }
560
561 static si_list_t *
562 search_service_all(si_mod_t *si)
563 {
564 return search_list(si, CATEGORY_SERVICE, si_service_all);
565 }
566
567 static si_item_t *
568 search_protocol_byname(si_mod_t *si, const char *name)
569 {
570 return search_item_byname(si, name, CATEGORY_PROTOCOL, si_protocol_byname);
571 }
572
573 static si_item_t *
574 search_protocol_bynumber(si_mod_t *si, int number)
575 {
576 return search_item_bynumber(si, (uint32_t)number, CATEGORY_PROTOCOL, si_protocol_bynumber);
577 }
578
579 static si_list_t *
580 search_protocol_all(si_mod_t *si)
581 {
582 return search_list(si, CATEGORY_PROTOCOL, si_protocol_all);
583 }
584
585 static si_item_t *
586 search_rpc_byname(si_mod_t *si, const char *name)
587 {
588 return search_item_byname(si, name, CATEGORY_RPC, si_rpc_byname);
589 }
590
591 static si_item_t *
592 search_rpc_bynumber(si_mod_t *si, int number)
593 {
594 int i, cat;
595 search_si_private_t *pp;
596 si_item_t *item;
597 si_mod_t *src;
598
599 if (si == NULL) return NULL;
600
601 pp = (search_si_private_t *)si->private;
602 if (pp == NULL) return NULL;
603
604 cat = CATEGORY_RPC;
605 i = 0;
606
607 while (NULL != (src = search_get_module(pp, cat, &i)))
608 {
609 item = si_rpc_bynumber(src, number);
610 if (item != NULL)
611 {
612 si_cache_add_item(search_cat_cache(pp, cat), src, item);
613 return item;
614 }
615 }
616
617 return NULL;
618 }
619
620 static si_list_t *
621 search_rpc_all(si_mod_t *si)
622 {
623 return search_list(si, CATEGORY_RPC, si_rpc_all);
624 }
625
626 static si_item_t *
627 search_fs_byspec(si_mod_t *si, const char *name)
628 {
629 return search_item_byname(si, name, CATEGORY_FS, si_fs_byspec);
630 }
631
632 static si_item_t *
633 search_fs_byfile(si_mod_t *si, const char *name)
634 {
635 return search_item_byname(si, name, CATEGORY_FS, si_fs_byfile);
636 }
637
638 static si_list_t *
639 search_fs_all(si_mod_t *si)
640 {
641 return search_list(si, CATEGORY_FS, si_fs_all);
642 }
643
644 static si_item_t *
645 search_mac_byname(si_mod_t *si, const char *name)
646 {
647 return search_item_byname(si, name, CATEGORY_MAC, si_mac_byname);
648 }
649
650 static si_item_t *
651 search_mac_bymac(si_mod_t *si, const char *mac)
652 {
653 return search_item_byname(si, mac, CATEGORY_MAC, si_mac_bymac);
654 }
655
656 static si_list_t *
657 search_mac_all(si_mod_t *si)
658 {
659 return search_list(si, CATEGORY_MAC, si_mac_all);
660 }
661
662 static si_list_t *
663 search_srv_byname(si_mod_t *si, const char* qname, const char *interface, uint32_t *err)
664 {
665 int i, cat;
666 si_list_t *list = NULL;
667 si_mod_t *src;
668 search_si_private_t *pp;
669
670 if (si == NULL) return NULL;
671
672 pp = (search_si_private_t *)si->private;
673 if (pp == NULL) return NULL;
674
675 cat = CATEGORY_SRV;
676 i = 0;
677
678 while (NULL != (src = search_get_module(pp, cat, &i)))
679 {
680 if (src == pp->cache) continue;
681
682 if (src->vtable->sim_srv_byname != NULL)
683 {
684 list = src->vtable->sim_srv_byname(src, qname, interface, err);
685 if (list != NULL) return list;
686 }
687 }
688
689 if ((i > 0) && (err != NULL)) *err = SI_STATUS_EAI_NONAME;
690 return NULL;
691 }
692
693 static int
694 search_wants_addrinfo(si_mod_t *si)
695 {
696 int i, cat;
697 si_mod_t *src;
698 search_si_private_t *pp;
699
700 if (si == NULL) return 0;
701
702 pp = (search_si_private_t *)si->private;
703 if (pp == NULL) return 0;
704
705 cat = CATEGORY_ADDRINFO;
706 i = 0;
707
708 while (NULL != (src = search_get_module(pp, cat, &i)))
709 {
710 if (src == pp->cache) continue;
711 if (src->vtable->sim_addrinfo != NULL) return 1;
712 }
713
714 return 0;
715 }
716
717 static si_list_t *
718 search_addrinfo(si_mod_t *si, const void *node, const void *serv, uint32_t family, uint32_t socktype, uint32_t protocol, uint32_t flags, const char *interface, uint32_t *err)
719 {
720 int i, cat;
721 search_si_private_t *pp;
722 si_list_t *list = NULL;
723 si_mod_t *src;
724
725 if (err != NULL) *err = SI_STATUS_EAI_FAIL;
726
727 if (si == NULL) return NULL;
728
729 pp = (search_si_private_t *)si->private;
730 if (pp == NULL) return NULL;
731
732 cat = CATEGORY_ADDRINFO;
733 i = 0;
734
735 while (NULL != (src = search_get_module(pp, cat, &i)))
736 {
737 if (src == pp->cache) continue;
738
739 if (src->vtable->sim_addrinfo != NULL)
740 {
741 list = src->vtable->sim_addrinfo(src, node, serv, family, socktype, protocol, flags, interface, err);
742 if (list != NULL) return list;
743 }
744 }
745
746 if ((i > 0) && (err != NULL)) *err = SI_STATUS_EAI_NONAME;
747 return NULL;
748 }
749
750 static si_item_t *
751 search_nameinfo(si_mod_t *si, const struct sockaddr *sa, int flags, const char *interface, uint32_t *err)
752 {
753 int i, cat;
754 search_si_private_t *pp;
755 si_item_t *item;
756 si_mod_t *src;
757
758 if (err != NULL) *err = SI_STATUS_EAI_FAIL;
759
760 if (si == NULL) return NULL;
761
762 pp = (search_si_private_t *)si->private;
763 if (pp == NULL) return NULL;
764
765 cat = CATEGORY_NAMEINFO;
766 i = 0;
767
768 while (NULL != (src = search_get_module(pp, cat, &i)))
769 {
770 item = si_nameinfo(src, sa, flags, interface, err);
771 if (item != NULL)
772 {
773 si_cache_add_item(search_cat_cache(pp, cat), src, item);
774 if (err != NULL) *err = SI_STATUS_NO_ERROR;
775 return item;
776 }
777 }
778
779 if ((i > 0) && (err != NULL)) *err = SI_STATUS_EAI_NONAME;
780 return NULL;
781 }
782
783 static int
784 search_is_valid(si_mod_t *si, si_item_t *item)
785 {
786 si_mod_t *src;
787
788 if (si == NULL) return 0;
789 if (item == NULL) return 0;
790 if (si->name == NULL) return 0;
791 if (item->src == NULL) return 0;
792
793 src = (si_mod_t *)item->src;
794
795 if (src->name == NULL) return 0;
796 if (string_not_equal(si->name, src->name)) return 0;
797 return 0;
798 }
799
800 si_mod_t *
801 si_module_static_search(void)
802 {
803 static const struct si_mod_vtable_s search_vtable =
804 {
805 .sim_close = &search_close,
806
807 .sim_is_valid = &search_is_valid,
808
809 .sim_user_byname = &search_user_byname,
810 .sim_user_byuid = &search_user_byuid,
811 .sim_user_all = &search_user_all,
812
813 .sim_group_byname = &search_group_byname,
814 .sim_group_bygid = &search_group_bygid,
815 .sim_group_all = &search_group_all,
816
817 .sim_grouplist = &search_groupist,
818
819 .sim_netgroup_byname = &search_netgroup_byname,
820 .sim_in_netgroup = &search_in_netgroup,
821
822 .sim_alias_byname = &search_alias_byname,
823 .sim_alias_all = &search_alias_all,
824
825 .sim_host_byname = &search_host_byname,
826 .sim_host_byaddr = &search_host_byaddr,
827 .sim_host_all = &search_host_all,
828
829 .sim_network_byname = &search_network_byname,
830 .sim_network_byaddr = &search_network_byaddr,
831 .sim_network_all = &search_network_all,
832
833 .sim_service_byname = &search_service_byname,
834 .sim_service_byport = &search_service_byport,
835 .sim_service_all = &search_service_all,
836
837 .sim_protocol_byname = &search_protocol_byname,
838 .sim_protocol_bynumber = &search_protocol_bynumber,
839 .sim_protocol_all = &search_protocol_all,
840
841 .sim_rpc_byname = &search_rpc_byname,
842 .sim_rpc_bynumber = &search_rpc_bynumber,
843 .sim_rpc_all = &search_rpc_all,
844
845 .sim_fs_byspec = &search_fs_byspec,
846 .sim_fs_byfile = &search_fs_byfile,
847 .sim_fs_all = &search_fs_all,
848
849 .sim_mac_byname = &search_mac_byname,
850 .sim_mac_bymac = &search_mac_bymac,
851 .sim_mac_all = &search_mac_all,
852
853 .sim_addrinfo = &search_addrinfo,
854 .sim_wants_addrinfo = &search_wants_addrinfo,
855 .sim_nameinfo = &search_nameinfo,
856
857 .sim_srv_byname = &search_srv_byname,
858 };
859
860 static si_mod_t si =
861 {
862 .vers = 1,
863 .refcount = 1,
864 .flags = SI_MOD_FLAG_STATIC,
865
866 .private = NULL,
867 .vtable = &search_vtable,
868 };
869
870 static dispatch_once_t once;
871
872 dispatch_once(&once, ^{
873 si.name = strdup("search");
874 search_si_private_t *pp = calloc(1, sizeof(search_si_private_t));
875 si.private = pp;
876
877 /*
878 * Default search order:
879 * 1) cache
880 * 2) DirectoryService/OpenDirectory (where available)
881 * 3) flat file
882 * 4) mDNSResponder
883 */
884
885 const char * const modules[] =
886 {
887 "default", // CATEGORY_DEFAULT
888 "cache",
889 #ifdef DS_AVAILABLE
890 "ds",
891 #endif
892 "mdns",
893 "file",
894 };
895
896 int count = sizeof(modules) / sizeof(char *);
897 si_module_config_modules_for_category(pp, CATEGORY_DEFAULT, count, modules);
898 pp->cache = pp->search_list[CATEGORY_DEFAULT].module[0];
899
900 FILE *conf = fopen(_PATH_SI_CONF, "r");
901 errno = 0;
902 if (conf != NULL)
903 {
904 forever
905 {
906 char *line = _fsi_get_line(conf);
907 if (line == NULL) break;
908
909 si_module_config_parse_line(pp, line);
910 free(line);
911 }
912
913 fclose(conf);
914 }
915 });
916
917 return &si;
918 }
919
920 static void
921 si_module_config_parse_line(search_si_private_t *pp, char *line)
922 {
923 if (line == NULL || line[0] == '#') {
924 return;
925 }
926
927 int ntokens = 0;
928 char **tokens = _fsi_tokenize(line, " : ", 0, &ntokens);
929
930 int cat = CATEGORY_INVALID;
931
932 if (string_equal(tokens[0], "default")) cat = CATEGORY_DEFAULT;
933 else if (string_equal(tokens[0], "user")) cat = CATEGORY_USER;
934 else if (string_equal(tokens[0], "group")) cat = CATEGORY_GROUP;
935 else if (string_equal(tokens[0], "grouplist")) cat = CATEGORY_GROUPLIST;
936 else if (string_equal(tokens[0], "netgroup")) cat = CATEGORY_NETGROUP;
937 else if (string_equal(tokens[0], "alias")) cat = CATEGORY_ALIAS;
938 else if (string_equal(tokens[0], "host")) cat = CATEGORY_HOST_IPV4;
939 else if (string_equal(tokens[0], "network")) cat = CATEGORY_NETWORK;
940 else if (string_equal(tokens[0], "service")) cat = CATEGORY_SERVICE;
941 else if (string_equal(tokens[0], "protocol")) cat = CATEGORY_PROTOCOL;
942 else if (string_equal(tokens[0], "rpc")) cat = CATEGORY_RPC;
943 else if (string_equal(tokens[0], "fs")) cat = CATEGORY_FS;
944 else if (string_equal(tokens[0], "mac")) cat = CATEGORY_MAC;
945 else if (string_equal(tokens[0], "addrinfo")) cat = CATEGORY_ADDRINFO;
946 else if (string_equal(tokens[0], "nameinfo")) cat = CATEGORY_NAMEINFO;
947
948 if (cat != CATEGORY_INVALID)
949 {
950 si_module_config_modules_for_category(pp, cat, ntokens, (const char * const *)tokens);
951 }
952
953 free(tokens);
954 }
955
956 static void
957 si_module_config_modules_for_category(search_si_private_t *pp, int cat, int ntokens, const char * const *tokens)
958 {
959 int count = ntokens - 1;
960 pp->search_list[cat].count = count;
961 if (count == 0)
962 {
963 return;
964 }
965
966 pp->search_list[cat].module = (si_mod_t **)calloc(pp->search_list[cat].count, sizeof(si_mod_t *));
967 pp->search_list[cat].module_flags = (uint32_t *)calloc(pp->search_list[cat].count, sizeof(uint32_t));
968 if ((pp->search_list[cat].module == NULL) || (pp->search_list[cat].module_flags == NULL))
969 {
970 free(pp->search_list[cat].module);
971 free(pp->search_list[cat].module_flags);
972 return;
973 }
974
975 int i, j;
976 for (i = 1, j = 0; i < ntokens; i++)
977 {
978 si_mod_t *mod = si_module_with_name(tokens[i]);
979 if (mod != NULL)
980 {
981 pp->search_list[cat].module[j] = mod;
982 j++;
983
984 if (string_equal(tokens[i], "cache"))
985 {
986 pp->search_list[cat].flags |= SEARCH_FLAG_CACHE_ENABLED;
987 }
988 }
989 }
990 }