1/*	$NetBSD$	*/
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
51typedef 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.  */
70static 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    if (msg_verbose)
86	msg_info("ni_lookup %s %s=%s", path, key_prop, key_value);
87
88    r = ni_open(NULL, ".", &domain);
89    if (r != NI_OK) {
90	msg_warn("ni_open `.': %d", r);
91	return NULL;
92    }
93    query = mymalloc(strlen(path) + strlen(key_prop) + 3 + strlen(key_value));
94    sprintf(query, "%s/%s=%s", path, key_prop, key_value);
95
96    for (;;) {
97
98	/*
99	 * What does it _mean_ if we find the directory but not the value?
100	 */
101	if (ni_pathsearch(domain, &dir, query) == NI_OK
102	    && ni_lookupprop(domain, &dir, val_prop, &values) == NI_OK)
103	    if (values.ni_namelist_len <= 0)
104		ni_namelist_free(&values);
105	    else {
106		unsigned int i, l, n;
107
108		for (i = l = 0; i < values.ni_namelist_len; i++)
109		    l += 1 + strlen(values.ni_namelist_val[i]);
110		if (result_cap < l) {
111		    if (result)
112			myfree(result);
113		    result_cap = l + 100;
114		    result = mymalloc(result_cap);
115		}
116		for (i = l = 0; i < values.ni_namelist_len; i++) {
117		    n = strlen(values.ni_namelist_val[i]);
118		    memcpy(result + l, values.ni_namelist_val[i], n);
119		    l += n;
120		    if (i < values.ni_namelist_len - 1)
121			result[l++] = ',';
122		}
123		result[l] = '\0';
124		return_val = result;
125		break;
126	    }
127
128	if (++depth >= NETINFO_MAX_DOMAIN_DEPTH) {
129	    msg_warn("ni_open: domain depth limit");
130	    break;
131	}
132	r = ni_open(domain, "..", &next_domain);
133	if (r != NI_OK) {
134	    if (r != NI_FAILED)
135		msg_warn("ni_open `..': %d", r);
136	    break;
137	}
138	ni_free(domain);
139	domain = next_domain;
140    }
141
142    ni_free(domain);
143    myfree(query);
144
145    return return_val;
146}
147
148/* dict_ni_lookup - find table entry */
149
150static const char *dict_ni_lookup(DICT *dict, const char *key)
151{
152    DICT_NI *d = (DICT_NI *) dict;
153
154    dict->error = 0;
155
156    /*
157     * Optionally fold the key.
158     */
159    if (dict->flags & DICT_FLAG_FOLD_FIX) {
160	if (dict->fold_buf == 0)
161	    dict->fold_buf = vstring_alloc(10);
162	vstring_strcpy(dict->fold_buf, key);
163	key = lowercase(vstring_str(dict->fold_buf));
164    }
165    return dict_ni_do_lookup(d->dict.name, NETINFO_PROP_KEY,
166			     key, NETINFO_PROP_VALUE);
167}
168
169/* dict_ni_close - disassociate from NetInfo map */
170
171static void dict_ni_close(DICT *dict)
172{
173    DICT_NI *d = (DICT_NI *) dict;
174
175    if (dict->fold_buf)
176	vstring_free(dict->fold_buf);
177    dict_free(dict);
178}
179
180/* dict_ni_open - create association with NetInfo map */
181
182DICT   *dict_ni_open(const char *path, int unused_flags, int dict_flags)
183{
184    DICT_NI *d = (void *) dict_alloc(DICT_TYPE_NETINFO, path, sizeof(*d));
185
186    d->dict.lookup = dict_ni_lookup;
187    d->dict.close = dict_ni_close;
188    d->dict.flags = dict_flags | DICT_FLAG_FIXED;
189    if (dict_flags & DICT_FLAG_FOLD_FIX)
190	d->dict.fold_buf = vstring_alloc(10);
191    d->dict.owner.status = DICT_OWNER_TRUSTED;
192
193    return (DICT_DEBUG (&d->dict));
194}
195
196#endif
197