Home | History | Annotate | Download | only in support
      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 subections 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 }
    318