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 }