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