prof_get.c revision 7934:6aeeafc994de
1/*
2 * prof_get.c --- routines that expose the public interfaces for
3 * 	querying items from the profile.
4 *
5 */
6
7#include "prof_int.h"
8#include <stdio.h>
9#include <string.h>
10#ifdef HAVE_STDLIB_H
11#include <stdlib.h>
12#endif
13#include <errno.h>
14#include <limits.h>
15
16/*
17 * These functions --- init_list(), end_list(), and add_to_list() are
18 * internal functions used to build up a null-terminated char ** list
19 * of strings to be returned by functions like profile_get_values.
20 *
21 * The profile_string_list structure is used for internal booking
22 * purposes to build up the list, which is returned in *ret_list by
23 * the end_list() function.
24 *
25 * The publicly exported interface for freeing char** list is
26 * profile_free_list().
27 */
28
29struct profile_string_list {
30	char	**list;
31	int	num;
32	int	max;
33};
34
35/*
36 * Initialize the string list abstraction.
37 */
38static errcode_t init_list(struct profile_string_list *list)
39{
40	list->num = 0;
41	list->max = 10;
42	list->list = malloc(list->max * sizeof(char *));
43	if (list->list == 0)
44		return ENOMEM;
45	list->list[0] = 0;
46	return 0;
47}
48
49/*
50 * Free any memory left over in the string abstraction, returning the
51 * built up list in *ret_list if it is non-null.
52 */
53static void end_list(struct profile_string_list *list, char ***ret_list)
54{
55	char	**cp;
56
57	if (list == 0)
58		return;
59
60	if (ret_list) {
61		*ret_list = list->list;
62		return;
63	} else {
64		for (cp = list->list; *cp; cp++)
65			free(*cp);
66		free(list->list);
67	}
68	list->num = list->max = 0;
69	list->list = 0;
70}
71
72/*
73 * Add a string to the list.
74 */
75static errcode_t add_to_list(struct profile_string_list *list, const char *str)
76{
77	char 	*newstr, **newlist;
78	int	newmax;
79
80	if (list->num+1 >= list->max) {
81		newmax = list->max + 10;
82		newlist = realloc(list->list, newmax * sizeof(char *));
83		if (newlist == 0)
84			return ENOMEM;
85		list->max = newmax;
86		list->list = newlist;
87	}
88	newstr = malloc(strlen(str)+1);
89	if (newstr == 0)
90		return ENOMEM;
91	strcpy(newstr, str);
92
93	list->list[list->num++] = newstr;
94	list->list[list->num] = 0;
95	return 0;
96}
97
98/*
99 * Return TRUE if the string is already a member of the list.
100 */
101static int is_list_member(struct profile_string_list *list, const char *str)
102{
103	char **cpp;
104
105	if (!list->list)
106		return 0;
107
108	for (cpp = list->list; *cpp; cpp++) {
109		if (!strcmp(*cpp, str))
110			return 1;
111	}
112	return 0;
113}
114
115/*
116 * This function frees a null-terminated list as returned by
117 * profile_get_values.
118 */
119void KRB5_CALLCONV profile_free_list(char **list)
120{
121    char	**cp;
122
123    if (list == 0)
124	    return;
125
126    for (cp = list; *cp; cp++)
127	free(*cp);
128    free(list);
129}
130
131errcode_t KRB5_CALLCONV
132profile_get_values(profile_t profile, const char *const *names,
133		   char ***ret_values)
134{
135	errcode_t		retval;
136	void			*state;
137	char			*value;
138	struct profile_string_list values;
139
140	if ((retval = profile_node_iterator_create(profile, names,
141						   PROFILE_ITER_RELATIONS_ONLY,
142						   &state)))
143		return retval;
144
145	if ((retval = init_list(&values)))
146		return retval;
147
148	do {
149		if ((retval = profile_node_iterator(&state, 0, 0, &value)))
150			goto cleanup;
151		if (value)
152			add_to_list(&values, value);
153	} while (state);
154
155	if (values.num == 0) {
156		retval = PROF_NO_RELATION;
157		goto cleanup;
158	}
159
160	end_list(&values, ret_values);
161	return 0;
162
163cleanup:
164	end_list(&values, 0);
165	return retval;
166}
167
168/*
169 * This function only gets the first value from the file; it is a
170 * helper function for profile_get_string, profile_get_integer, etc.
171 */
172errcode_t profile_get_value(profile_t profile, const char **names,
173			    const char **ret_value)
174{
175	errcode_t		retval;
176	void			*state;
177	char			*value;
178
179	if ((retval = profile_node_iterator_create(profile, names,
180						   PROFILE_ITER_RELATIONS_ONLY,
181						   &state)))
182		return retval;
183
184	if ((retval = profile_node_iterator(&state, 0, 0, &value)))
185		goto cleanup;
186
187	if (value)
188		*ret_value = value;
189	else
190		retval = PROF_NO_RELATION;
191
192cleanup:
193	profile_node_iterator_free(&state);
194	return retval;
195}
196
197errcode_t KRB5_CALLCONV
198profile_get_string(profile_t profile, const char *name, const char *subname,
199		   const char *subsubname, const char *def_val,
200		   char **ret_string)
201{
202	const char	*value;
203	errcode_t	retval;
204	const char	*names[4];
205
206	if (profile) {
207		names[0] = name;
208		names[1] = subname;
209		names[2] = subsubname;
210		names[3] = 0;
211		retval = profile_get_value(profile, names, &value);
212		if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION)
213			value = def_val;
214		else if (retval)
215			return retval;
216	} else
217		value = def_val;
218
219	if (value) {
220		*ret_string = malloc(strlen(value)+1);
221		if (*ret_string == 0)
222			return ENOMEM;
223		strcpy(*ret_string, value);
224	} else
225		*ret_string = 0;
226	return 0;
227}
228
229errcode_t KRB5_CALLCONV
230profile_get_integer(profile_t profile, const char *name, const char *subname,
231		    const char *subsubname, int def_val, int *ret_int)
232{
233	const char	*value;
234	errcode_t	retval;
235	const char	*names[4];
236	char            *end_value;
237	long		ret_long;
238
239	*ret_int = def_val;
240	if (profile == 0)
241		return 0;
242
243	names[0] = name;
244	names[1] = subname;
245	names[2] = subsubname;
246	names[3] = 0;
247	retval = profile_get_value(profile, names, &value);
248	if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) {
249		*ret_int = def_val;
250		return 0;
251	} else if (retval)
252		return retval;
253
254	if (value[0] == 0)
255	    /* Empty string is no good.  */
256	    return PROF_BAD_INTEGER;
257	errno = 0;
258	ret_long = strtol (value, &end_value, 10);
259
260	/* Overflow or underflow.  */
261	if ((ret_long == LONG_MIN || ret_long == LONG_MAX) && errno != 0)
262	    return PROF_BAD_INTEGER;
263	/* Value outside "int" range.  */
264	if ((long) (int) ret_long != ret_long)
265	    return PROF_BAD_INTEGER;
266	/* Garbage in string.  */
267	if (end_value != value + strlen (value))
268	    return PROF_BAD_INTEGER;
269
270
271	*ret_int = ret_long;
272	return 0;
273}
274
275static const char *const conf_yes[] = {
276    "y", "yes", "true", "t", "1", "on",
277    0,
278};
279
280static const char *const conf_no[] = {
281    "n", "no", "false", "nil", "0", "off",
282    0,
283};
284
285static errcode_t
286profile_parse_boolean(const char *s, int *ret_boolean)
287{
288    const char *const *p;
289
290    if (ret_boolean == NULL)
291    	return PROF_EINVAL;
292
293    for(p=conf_yes; *p; p++) {
294		if (!strcasecmp(*p,s)) {
295			*ret_boolean = 1;
296	    	return 0;
297		}
298    }
299
300    for(p=conf_no; *p; p++) {
301		if (!strcasecmp(*p,s)) {
302			*ret_boolean = 0;
303			return 0;
304		}
305    }
306
307	return PROF_BAD_BOOLEAN;
308}
309
310errcode_t KRB5_CALLCONV
311profile_get_boolean(profile_t profile, const char *name, const char *subname,
312		    const char *subsubname, int def_val, int *ret_boolean)
313{
314	const char	*value;
315	errcode_t	retval;
316	const char	*names[4];
317
318	if (profile == 0) {
319		*ret_boolean = def_val;
320		return 0;
321	}
322
323	names[0] = name;
324	names[1] = subname;
325	names[2] = subsubname;
326	names[3] = 0;
327	retval = profile_get_value(profile, names, &value);
328	if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) {
329		*ret_boolean = def_val;
330		return 0;
331	} else if (retval)
332		return retval;
333
334	return profile_parse_boolean (value, ret_boolean);
335}
336
337/*
338 * This function will return the list of the names of subections in the
339 * under the specified section name.
340 */
341errcode_t KRB5_CALLCONV
342profile_get_subsection_names(profile_t profile, const char **names,
343			     char ***ret_names)
344{
345	errcode_t		retval;
346	void			*state;
347	char			*name;
348	struct profile_string_list values;
349
350	if ((retval = profile_node_iterator_create(profile, names,
351		   PROFILE_ITER_LIST_SECTION | PROFILE_ITER_SECTIONS_ONLY,
352		   &state)))
353		return retval;
354
355	if ((retval = init_list(&values)))
356		return retval;
357
358	do {
359		if ((retval = profile_node_iterator(&state, 0, &name, 0)))
360			goto cleanup;
361		if (name)
362			add_to_list(&values, name);
363	} while (state);
364
365	end_list(&values, ret_names);
366	return 0;
367
368cleanup:
369	end_list(&values, 0);
370	return retval;
371}
372
373/*
374 * This function will return the list of the names of relations in the
375 * under the specified section name.
376 */
377errcode_t KRB5_CALLCONV
378profile_get_relation_names(profile_t profile, const char **names,
379			   char ***ret_names)
380{
381	errcode_t		retval;
382	void			*state;
383	char			*name;
384	struct profile_string_list values;
385
386	if ((retval = profile_node_iterator_create(profile, names,
387		   PROFILE_ITER_LIST_SECTION | PROFILE_ITER_RELATIONS_ONLY,
388		   &state)))
389		return retval;
390
391	if ((retval = init_list(&values)))
392		return retval;
393
394	do {
395		if ((retval = profile_node_iterator(&state, 0, &name, 0)))
396			goto cleanup;
397		if (name && !is_list_member(&values, name))
398			add_to_list(&values, name);
399	} while (state);
400
401	end_list(&values, ret_names);
402	return 0;
403
404cleanup:
405	end_list(&values, 0);
406	return retval;
407}
408
409errcode_t KRB5_CALLCONV
410profile_iterator_create(profile_t profile, const char *const *names, int flags,
411			void **ret_iter)
412{
413	return profile_node_iterator_create(profile, names, flags, ret_iter);
414}
415
416void KRB5_CALLCONV
417profile_iterator_free(void **iter_p)
418{
419	profile_node_iterator_free(iter_p);
420}
421
422errcode_t KRB5_CALLCONV
423profile_iterator(void **iter_p, char **ret_name, char **ret_value)
424{
425	char *name, *value;
426	errcode_t	retval;
427
428	retval = profile_node_iterator(iter_p, 0, &name, &value);
429	if (retval)
430		return retval;
431
432	if (ret_name) {
433		if (name) {
434			*ret_name = malloc(strlen(name)+1);
435			if (!*ret_name)
436				return ENOMEM;
437			strcpy(*ret_name, name);
438		} else
439			*ret_name = 0;
440	}
441	if (ret_value) {
442		if (value) {
443			*ret_value = malloc(strlen(value)+1);
444			if (!*ret_value) {
445				if (ret_name) {
446					free(*ret_name);
447					*ret_name = 0;
448				}
449				return ENOMEM;
450			}
451			strcpy(*ret_value, value);
452		} else
453			*ret_value = 0;
454	}
455	return 0;
456}
457
458void KRB5_CALLCONV
459profile_release_string(char *str)
460{
461	free(str);
462}
463