1 /*	$NetBSD: dict_ni.c,v 1.1.1.1 2009/06/23 10:08:59 tron Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	dict_ni 3
6 /* SUMMARY
7 /*	dictionary manager interface to NetInfo
8 /* SYNOPSIS
9 /*	#include <dict_ni.h>
10 /*
11 /*	DICT	*dict_ni_open(path, dummy, dict_flags)
12 /*	char	*path;
13 /*	int	dummy;
14 /*	int	dict_flags;
15 /* DESCRIPTION
16 /*	dict_ni_open() `opens' the named NetInfo database. The result is
17 /*	a pointer to a structure that can be used to access the dictionary
18 /*	using the generic methods documented in dict_open(3).
19 /* DIAGNOSTICS
20 /*	dict_ni_register() returns 0 in case of success, -1 in case
21 /*	of problems.
22 /*	Fatal errors: NetInfo errors, out of memory.
23 /* SEE ALSO
24 /*	dict(3) generic dictionary manager
25 /*	netinfo(3N) data base subroutines
26 /* AUTHOR(S)
27 /*	Pieter Schoenmakers
28 /*	Eindhoven University of Technology
29 /*	P.O. Box 513
30 /*	5600 MB Eindhoven
31 /*	The Netherlands
32 /*--*/
33 
34 #include "sys_defs.h"
35 
36 #ifdef HAS_NETINFO
37 
38 /* System library. */
39 
40 #include <stdio.h>
41 #include <netinfo/ni.h>
42 
43 /* Utility library. */
44 
45 #include "dict.h"
46 #include "dict_ni.h"
47 #include "msg.h"
48 #include "mymalloc.h"
49 #include "stringops.h"
50 
51 typedef struct {
52     DICT    dict;			/* my super */
53     char   *path;			/* directory path */
54 } DICT_NI;
55 
56  /*
57   * We'd like other possibilities, but that is not possible in the current
58   * dictionary setup...  An example of a different setup: use `members' for
59   * multi-valued lookups (to be compatible with /aliases), and `value' for
60   * single-valued tables.
61   */
62 #define NETINFO_PROP_KEY	"name"
63 #define NETINFO_PROP_VALUE	"members"
64 #define NETINFO_VALUE_SEP	 ","
65 
66 #define NETINFO_MAX_DOMAIN_DEPTH	100
67 
68 /* Hard worker doing lookups.	Returned value is statically allocated and
69    reused each call.  */
70 static const char *dict_ni_do_lookup(char *path, char *key_prop,
71 			              const char *key_value, char *val_prop)
72 {
73     unsigned int result_cap = 0;
74     static char *result = 0;
75 
76     char   *return_val = 0;
77     ni_namelist values;
78     int     depth = 0;
79     void   *domain;
80     void   *next_domain;
81     char   *query;
82     ni_status r;
83     ni_id   dir;
84 
85     dict_errno = 0;
86 
87     if (msg_verbose)
88 	msg_info("ni_lookup %s %s=%s", path, key_prop, key_value);
89 
90     r = ni_open(NULL, ".", &domain);
91     if (r != NI_OK) {
92 	msg_warn("ni_open `.': %d", r);
93 	return NULL;
94     }
95     query = alloca(strlen(path) + strlen(key_prop) + 3 + strlen(key_value));
96     sprintf(query, "%s/%s=%s", path, key_prop, key_value);
97 
98     for (;;) {
99 
100 	/*
101 	 * What does it _mean_ if we find the directory but not the value?
102 	 */
103 	if (ni_pathsearch(domain, &dir, query) == NI_OK
104 	    && ni_lookupprop(domain, &dir, val_prop, &values) == NI_OK)
105 	    if (values.ni_namelist_len <= 0)
106 		ni_namelist_free(&values);
107 	    else {
108 		unsigned int i, l, n;
109 
110 		for (i = l = 0; i < values.ni_namelist_len; i++)
111 		    l += 1 + strlen(values.ni_namelist_val[i]);
112 		if (result_cap < l) {
113 		    if (result)
114 			myfree(result);
115 		    result_cap = l + 100;
116 		    result = mymalloc(result_cap);
117 		}
118 		for (i = l = 0; i < values.ni_namelist_len; i++) {
119 		    n = strlen(values.ni_namelist_val[i]);
120 		    memcpy(result + l, values.ni_namelist_val[i], n);
121 		    l += n;
122 		    if (i < values.ni_namelist_len - 1)
123 			result[l++] = ',';
124 		}
125 		result[l] = '\0';
126 		return_val = result;
127 		break;
128 	    }
129 
130 	if (++depth >= NETINFO_MAX_DOMAIN_DEPTH) {
131 	    msg_warn("ni_open: domain depth limit");
132 	    break;
133 	}
134 	r = ni_open(domain, "..", &next_domain);
135 	if (r != NI_OK) {
136 	    if (r != NI_FAILED)
137 		msg_warn("ni_open `..': %d", r);
138 	    break;
139 	}
140 	ni_free(domain);
141 	domain = next_domain;
142     }
143 
144     ni_free(domain);
145 
146     return return_val;
147 }
148 
149 /* dict_ni_lookup - find table entry */
150 
151 static const char *dict_ni_lookup(DICT *dict, const char *key)
152 {
153     DICT_NI *d = (DICT_NI *) dict;
154 
155     /*
156      * Optionally fold the key.
157      */
158     if (dict->flags & DICT_FLAG_FOLD_FIX) {
159 	if (dict->fold_buf == 0)
160 	    dict->fold_buf = vstring_alloc(10);
161 	vstring_strcpy(dict->fold_buf, key);
162 	key = lowercase(vstring_str(dict->fold_buf));
163     }
164     return dict_ni_do_lookup(d->dict.name, NETINFO_PROP_KEY,
165 			     key, NETINFO_PROP_VALUE);
166 }
167 
168 /* dict_ni_close - disassociate from NetInfo map */
169 
170 static void dict_ni_close(DICT *dict)
171 {
172     DICT_NI *d = (DICT_NI *) dict;
173 
174     if (dict->fold_buf)
175 	vstring_free(dict->fold_buf);
176     dict_free(dict);
177 }
178 
179 /* dict_ni_open - create association with NetInfo map */
180 
181 DICT   *dict_ni_open(const char *path, int unused_flags, int dict_flags)
182 {
183     DICT_NI *d = (void *) dict_alloc(DICT_TYPE_NETINFO, path, sizeof(*d));
184 
185     d->dict.lookup = dict_ni_lookup;
186     d->dict.close = dict_ni_close;
187     d->dict.flags = dict_flags | DICT_FLAG_FIXED;
188     if (dict_flags & DICT_FLAG_FOLD_FIX)
189 	d->dict.fold_buf = vstring_alloc(10);
190 
191     return (DICT_DEBUG (&d->dict));
192 }
193 
194 #endif
195