Home | History | Annotate | Download | only in e2fsck
      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 }
    310