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