OSDN Git Service

merge in master-release history after reset to 2079d768f79f636223d89b988a30209adf8dddbe
[android-x86/external-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 <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  */
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  */
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  */
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  */
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  */
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
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
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
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
255 profile_release_string(char *str)
256 {
257         free(str);
258 }
259
260 errcode_t
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 }