L4Re/departure

libext2fs/lib/libsupport/profile_helpers.c

617:2733e5770ee9
9 months ago Paul Boddie Made the run command wait for completion, introducing the spawn command to run programs in the background. Introduced conveniences for waiting for the last job to be initiated and for piping from the last job, also subscribing to signals from pipe-supplying jobs so that they may be transparently removed from the job list upon completion. Augmented the job listing with the "+" notation familiar from Unix. Prevented new jobs from being started when no job slots are available.
     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 }