Whamcloud - gitweb
e2fsck: regression tests for INCOMPAT_MMP feature
[tools/e2fsprogs.git] / e2fsck / 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 "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
43 struct profile_string_list {
44         char    **list;
45         int     num;
46         int     max;
47 };
48
49 /*
50  * Initialize the string list abstraction.
51  */
52 static 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  */
67 static 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  */
89 static 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  */
111 static 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  */
129 void 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
141 errcode_t
142 profile_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
173 cleanup:
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  */
182 errcode_t
183 profile_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
209 cleanup:
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  */
218 errcode_t
219 profile_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
249 cleanup:
250         end_list(&values, 0);
251         return retval;
252 }
253
254
255 void
256 profile_release_string(char *str)
257 {
258         free(str);
259 }
260
261 errcode_t
262 profile_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 }