1 /*
2 * profile_helpers.c -- Helper functions for the profile library
3 *
4 * These functions are not part of the "core" profile library, and do
5 * not require access to the internal functions and data structures of
6 * the profile library. They are mainly convenience functions for
7 * programs that want to do something unusual such as obtaining the
8 * list of sections or relations, or accessing multiple values from a
9 * relation that is listed more than once. This functionality can all
10 * be done using the profile_iterator abstraction, but it is less
11 * convenient.
12 *
13 * Copyright (C) 2006 by Theodore Ts'o.
14 *
15 * %Begin-Header%
16 * This file may be redistributed under the terms of the GNU Public
17 * License.
18 * %End-Header%
19 */
20
21 #include <stdlib.h>
22 #include <string.h>
23 #include <errno.h>
24
25 #include <et/com_err.h>
26 #include "profile.h"
27 #include "prof_err.h"
28
29 /*
30 * These functions --- init_list(), end_list(), and add_to_list() are
31 * internal functions used to build up a null-terminated char ** list
32 * of strings to be returned by functions like profile_get_values.
33 *
34 * The profile_string_list structure is used for internal booking
35 * purposes to build up the list, which is returned in *ret_list by
36 * the end_list() function.
37 *
38 * The publicly exported interface for freeing char** list is
39 * profile_free_list().
40 */
41
42 struct profile_string_list {
43 char **list;
44 int num;
45 int max;
46 };
47
48 /*
49 * Initialize the string list abstraction.
50 */
init_list(struct profile_string_list * list)51 static errcode_t init_list(struct profile_string_list *list)
52 {
53 list->num = 0;
54 list->max = 10;
55 list->list = malloc(list->max * sizeof(char *));
56 if (list->list == 0)
57 return ENOMEM;
58 list->list[0] = 0;
59 return 0;
60 }
61
62 /*
63 * Free any memory left over in the string abstraction, returning the
64 * built up list in *ret_list if it is non-null.
65 */
end_list(struct profile_string_list * list,char *** ret_list)66 static void end_list(struct profile_string_list *list, char ***ret_list)
67 {
68 char **cp;
69
70 if (list == 0)
71 return;
72
73 if (ret_list) {
74 *ret_list = list->list;
75 return;
76 } else {
77 for (cp = list->list; *cp; cp++)
78 free(*cp);
79 free(list->list);
80 }
81 list->num = list->max = 0;
82 list->list = 0;
83 }
84
85 /*
86 * Add a string to the list.
87 */
add_to_list(struct profile_string_list * list,char * str)88 static errcode_t add_to_list(struct profile_string_list *list, char *str)
89 {
90 char **newlist;
91 int newmax;
92
93 if (list->num+1 >= list->max) {
94 newmax = list->max + 10;
95 newlist = realloc(list->list, newmax * sizeof(char *));
96 if (newlist == 0)
97 return ENOMEM;
98 list->max = newmax;
99 list->list = newlist;
100 }
101
102 list->list[list->num++] = str;
103 list->list[list->num] = 0;
104 return 0;
105 }
106
107 /*
108 * Return TRUE if the string is already a member of the list.
109 */
is_list_member(struct profile_string_list * list,const char * str)110 static int is_list_member(struct profile_string_list *list, const char *str)
111 {
112 char **cpp;
113
114 if (!list->list)
115 return 0;
116
117 for (cpp = list->list; *cpp; cpp++) {
118 if (!strcmp(*cpp, str))
119 return 1;
120 }
121 return 0;
122 }
123
124 /*
125 * This function frees a null-terminated list as returned by
126 * profile_get_values.
127 */
profile_free_list(char ** list)128 void profile_free_list(char **list)
129 {
130 char **cp;
131
132 if (list == 0)
133 return;
134
135 for (cp = list; *cp; cp++)
136 free(*cp);
137 free(list);
138 }
139
140 errcode_t
profile_get_values(profile_t profile,const char * const * names,char *** ret_values)141 profile_get_values(profile_t profile, const char *const *names,
142 char ***ret_values)
143 {
144 errcode_t retval;
145 void *state;
146 char *value;
147 struct profile_string_list values;
148
149 if ((retval = profile_iterator_create(profile, names,
150 PROFILE_ITER_RELATIONS_ONLY,
151 &state)))
152 return retval;
153
154 if ((retval = init_list(&values)))
155 return retval;
156
157 do {
158 if ((retval = profile_iterator(&state, 0, &value)))
159 goto cleanup;
160 if (value)
161 add_to_list(&values, value);
162 } while (state);
163
164 if (values.num == 0) {
165 retval = PROF_NO_RELATION;
166 goto cleanup;
167 }
168
169 end_list(&values, ret_values);
170 return 0;
171
172 cleanup:
173 end_list(&values, 0);
174 return retval;
175 }
176
177 /*
178 * This function will return the list of the names of subections in the
179 * under the specified section name.
180 */
181 errcode_t
profile_get_subsection_names(profile_t profile,const char ** names,char *** ret_names)182 profile_get_subsection_names(profile_t profile, const char **names,
183 char ***ret_names)
184 {
185 errcode_t retval;
186 void *state;
187 char *name;
188 struct profile_string_list values;
189
190 if ((retval = profile_iterator_create(profile, names,
191 PROFILE_ITER_LIST_SECTION | PROFILE_ITER_SECTIONS_ONLY,
192 &state)))
193 return retval;
194
195 if ((retval = init_list(&values)))
196 return retval;
197
198 do {
199 if ((retval = profile_iterator(&state, &name, 0)))
200 goto cleanup;
201 if (name)
202 add_to_list(&values, name);
203 } while (state);
204
205 end_list(&values, ret_names);
206 return 0;
207
208 cleanup:
209 end_list(&values, 0);
210 return retval;
211 }
212
213 /*
214 * This function will return the list of the names of relations in the
215 * under the specified section name.
216 */
217 errcode_t
profile_get_relation_names(profile_t profile,const char ** names,char *** ret_names)218 profile_get_relation_names(profile_t profile, const char **names,
219 char ***ret_names)
220 {
221 errcode_t retval;
222 void *state;
223 char *name;
224 struct profile_string_list values;
225
226 if ((retval = profile_iterator_create(profile, names,
227 PROFILE_ITER_LIST_SECTION | PROFILE_ITER_RELATIONS_ONLY,
228 &state)))
229 return retval;
230
231 if ((retval = init_list(&values)))
232 return retval;
233
234 do {
235 if ((retval = profile_iterator(&state, &name, 0)))
236 goto cleanup;
237 if (name) {
238 if (is_list_member(&values, name))
239 free(name);
240 else
241 add_to_list(&values, name);
242 }
243 } while (state);
244
245 end_list(&values, ret_names);
246 return 0;
247
248 cleanup:
249 end_list(&values, 0);
250 return retval;
251 }
252
253
254 void
profile_release_string(char * str)255 profile_release_string(char *str)
256 {
257 free(str);
258 }
259
260 errcode_t
profile_init_path(const char * filepath,profile_t * ret_profile)261 profile_init_path(const char * filepath,
262 profile_t *ret_profile)
263 {
264 int n_entries, i;
265 unsigned int ent_len;
266 const char *s, *t;
267 char **filenames;
268 errcode_t retval;
269
270 /* count the distinct filename components */
271 for(s = filepath, n_entries = 1; *s; s++) {
272 if (*s == ':')
273 n_entries++;
274 }
275
276 /* the array is NULL terminated */
277 filenames = (char **) malloc((n_entries+1) * sizeof(char*));
278 if (filenames == 0)
279 return ENOMEM;
280
281 /* measure, copy, and skip each one */
282 for(s = filepath, i=0; (t = strchr(s, ':')) || (t=s+strlen(s)); s=t+1, i++) {
283 ent_len = t-s;
284 filenames[i] = (char*) malloc(ent_len + 1);
285 if (filenames[i] == 0) {
286 /* if malloc fails, free the ones that worked */
287 while(--i >= 0) free(filenames[i]);
288 free(filenames);
289 return ENOMEM;
290 }
291 strncpy(filenames[i], s, ent_len);
292 filenames[i][ent_len] = 0;
293 if (*t == 0) {
294 i++;
295 break;
296 }
297 }
298 /* cap the array */
299 filenames[i] = 0;
300
301 retval = profile_init((const char **) filenames,
302 ret_profile);
303
304 /* count back down and free the entries */
305 while(--i >= 0) free(filenames[i]);
306 free(filenames);
307
308 return retval;
309 }
310