summaryrefslogtreecommitdiffstats
path: root/src/util/dict_ni.c
blob: 3f625599f4059d93e49fd3b3fd86d818c212f30a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/*++
/* NAME
/*	dict_ni 3
/* SUMMARY
/*	dictionary manager interface to NetInfo
/* SYNOPSIS
/*	#include <dict_ni.h>
/*
/*	DICT	*dict_ni_open(path, dummy, dict_flags)
/*	char	*path;
/*	int	dummy;
/*	int	dict_flags;
/* DESCRIPTION
/*	dict_ni_open() `opens' the named NetInfo database. The result is
/*	a pointer to a structure that can be used to access the dictionary
/*	using the generic methods documented in dict_open(3).
/* DIAGNOSTICS
/*	dict_ni_register() returns 0 in case of success, -1 in case
/*	of problems.
/*	Fatal errors: NetInfo errors, out of memory.
/* SEE ALSO
/*	dict(3) generic dictionary manager
/*	netinfo(3N) data base subroutines
/* AUTHOR(S)
/*	Pieter Schoenmakers
/*	Eindhoven University of Technology
/*	P.O. Box 513
/*	5600 MB Eindhoven
/*	The Netherlands
/*--*/

#include "sys_defs.h"

#ifdef HAS_NETINFO

/* System library. */

#include <stdio.h>
#include <netinfo/ni.h>

/* Utility library. */

#include "dict.h"
#include "dict_ni.h"
#include "msg.h"
#include "mymalloc.h"
#include "stringops.h"

typedef struct {
    DICT    dict;			/* my super */
    char   *path;			/* directory path */
} DICT_NI;

 /*
  * We'd like other possibilities, but that is not possible in the current
  * dictionary setup...  An example of a different setup: use `members' for
  * multi-valued lookups (to be compatible with /aliases), and `value' for
  * single-valued tables.
  */
#define NETINFO_PROP_KEY	"name"
#define NETINFO_PROP_VALUE	"members"
#define NETINFO_VALUE_SEP	 ","

#define NETINFO_MAX_DOMAIN_DEPTH	100

/* Hard worker doing lookups.	Returned value is statically allocated and
   reused each call.  */
static const char *dict_ni_do_lookup(char *path, char *key_prop,
			              const char *key_value, char *val_prop)
{
    unsigned int result_cap = 0;
    static char *result = 0;

    char   *return_val = 0;
    ni_namelist values;
    int     depth = 0;
    void   *domain;
    void   *next_domain;
    char   *query;
    ni_status r;
    ni_id   dir;

    if (msg_verbose)
	msg_info("ni_lookup %s %s=%s", path, key_prop, key_value);

    r = ni_open(NULL, ".", &domain);
    if (r != NI_OK) {
	msg_warn("ni_open `.': %d", r);
	return NULL;
    }
    query = mymalloc(strlen(path) + strlen(key_prop) + 3 + strlen(key_value));
    sprintf(query, "%s/%s=%s", path, key_prop, key_value);

    for (;;) {

	/*
	 * What does it _mean_ if we find the directory but not the value?
	 */
	if (ni_pathsearch(domain, &dir, query) == NI_OK
	    && ni_lookupprop(domain, &dir, val_prop, &values) == NI_OK)
	    if (values.ni_namelist_len <= 0)
		ni_namelist_free(&values);
	    else {
		unsigned int i, l, n;

		for (i = l = 0; i < values.ni_namelist_len; i++)
		    l += 1 + strlen(values.ni_namelist_val[i]);
		if (result_cap < l) {
		    if (result)
			myfree(result);
		    result_cap = l + 100;
		    result = mymalloc(result_cap);
		}
		for (i = l = 0; i < values.ni_namelist_len; i++) {
		    n = strlen(values.ni_namelist_val[i]);
		    memcpy(result + l, values.ni_namelist_val[i], n);
		    l += n;
		    if (i < values.ni_namelist_len - 1)
			result[l++] = ',';
		}
		result[l] = '\0';
		return_val = result;
		break;
	    }

	if (++depth >= NETINFO_MAX_DOMAIN_DEPTH) {
	    msg_warn("ni_open: domain depth limit");
	    break;
	}
	r = ni_open(domain, "..", &next_domain);
	if (r != NI_OK) {
	    if (r != NI_FAILED)
		msg_warn("ni_open `..': %d", r);
	    break;
	}
	ni_free(domain);
	domain = next_domain;
    }

    ni_free(domain);
    myfree(query);

    return return_val;
}

/* dict_ni_lookup - find table entry */

static const char *dict_ni_lookup(DICT *dict, const char *key)
{
    DICT_NI *d = (DICT_NI *) dict;

    dict->error = 0;

    /*
     * Optionally fold the key.
     */
    if (dict->flags & DICT_FLAG_FOLD_FIX) {
	if (dict->fold_buf == 0)
	    dict->fold_buf = vstring_alloc(10);
	vstring_strcpy(dict->fold_buf, key);
	key = lowercase(vstring_str(dict->fold_buf));
    }
    return dict_ni_do_lookup(d->dict.name, NETINFO_PROP_KEY,
			     key, NETINFO_PROP_VALUE);
}

/* dict_ni_close - disassociate from NetInfo map */

static void dict_ni_close(DICT *dict)
{
    DICT_NI *d = (DICT_NI *) dict;

    if (dict->fold_buf)
	vstring_free(dict->fold_buf);
    dict_free(dict);
}

/* dict_ni_open - create association with NetInfo map */

DICT   *dict_ni_open(const char *path, int unused_flags, int dict_flags)
{
    DICT_NI *d = (void *) dict_alloc(DICT_TYPE_NETINFO, path, sizeof(*d));

    d->dict.lookup = dict_ni_lookup;
    d->dict.close = dict_ni_close;
    d->dict.flags = dict_flags | DICT_FLAG_FIXED;
    if (dict_flags & DICT_FLAG_FOLD_FIX)
	d->dict.fold_buf = vstring_alloc(10);
    d->dict.owner.status = DICT_OWNER_TRUSTED;

    return (DICT_DEBUG (&d->dict));
}

#endif