File:  [Qemu by Fabrice Bellard] / qemu / envlist.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:33:41 2018 UTC (3 years, 4 months ago) by root
Branches: qemu, MAIN
CVS tags: qemu1101, qemu1001, qemu1000, qemu0151, qemu0150, qemu0141, qemu0140, qemu0130, qemu0125, qemu0124, qemu0123, qemu0122, qemu0121, qemu0120, HEAD
qemu 0.12.0

    1: #include <assert.h>
    2: #include <errno.h>
    3: #include <stdlib.h>
    4: #include <string.h>
    5: #include <unistd.h>
    6: 
    7: #include "qemu-queue.h"
    8: #include "envlist.h"
    9: 
   10: struct envlist_entry {
   11: 	const char *ev_var;			/* actual env value */
   12: 	QLIST_ENTRY(envlist_entry) ev_link;
   13: };
   14: 
   15: struct envlist {
   16: 	QLIST_HEAD(, envlist_entry) el_entries;	/* actual entries */
   17: 	size_t el_count;			/* number of entries */
   18: };
   19: 
   20: static int envlist_parse(envlist_t *envlist,
   21:     const char *env, int (*)(envlist_t *, const char *));
   22: 
   23: /*
   24:  * Allocates new envlist and returns pointer to that or
   25:  * NULL in case of error.
   26:  */
   27: envlist_t *
   28: envlist_create(void)
   29: {
   30: 	envlist_t *envlist;
   31: 
   32: 	if ((envlist = malloc(sizeof (*envlist))) == NULL)
   33: 		return (NULL);
   34: 
   35: 	QLIST_INIT(&envlist->el_entries);
   36: 	envlist->el_count = 0;
   37: 
   38: 	return (envlist);
   39: }
   40: 
   41: /*
   42:  * Releases given envlist and its entries.
   43:  */
   44: void
   45: envlist_free(envlist_t *envlist)
   46: {
   47: 	struct envlist_entry *entry;
   48: 
   49: 	assert(envlist != NULL);
   50: 
   51: 	while (envlist->el_entries.lh_first != NULL) {
   52: 		entry = envlist->el_entries.lh_first;
   53: 		QLIST_REMOVE(entry, ev_link);
   54: 
   55: 		free((char *)entry->ev_var);
   56: 		free(entry);
   57: 	}
   58: 	free(envlist);
   59: }
   60: 
   61: /*
   62:  * Parses comma separated list of set/modify environment
   63:  * variable entries and updates given enlist accordingly.
   64:  *
   65:  * For example:
   66:  *     envlist_parse(el, "HOME=foo,SHELL=/bin/sh");
   67:  *
   68:  * inserts/sets environment variables HOME and SHELL.
   69:  *
   70:  * Returns 0 on success, errno otherwise.
   71:  */
   72: int
   73: envlist_parse_set(envlist_t *envlist, const char *env)
   74: {
   75: 	return (envlist_parse(envlist, env, &envlist_setenv));
   76: }
   77: 
   78: /*
   79:  * Parses comma separated list of unset environment variable
   80:  * entries and removes given variables from given envlist.
   81:  *
   82:  * Returns 0 on success, errno otherwise.
   83:  */
   84: int
   85: envlist_parse_unset(envlist_t *envlist, const char *env)
   86: {
   87: 	return (envlist_parse(envlist, env, &envlist_unsetenv));
   88: }
   89: 
   90: /*
   91:  * Parses comma separated list of set, modify or unset entries
   92:  * and calls given callback for each entry.
   93:  *
   94:  * Returns 0 in case of success, errno otherwise.
   95:  */
   96: static int
   97: envlist_parse(envlist_t *envlist, const char *env,
   98:     int (*callback)(envlist_t *, const char *))
   99: {
  100: 	char *tmpenv, *envvar;
  101: 	char *envsave = NULL;
  102: 
  103: 	assert(callback != NULL);
  104: 
  105: 	if ((envlist == NULL) || (env == NULL))
  106: 		return (EINVAL);
  107: 
  108: 	/*
  109: 	 * We need to make temporary copy of the env string
  110: 	 * as strtok_r(3) modifies it while it tokenizes.
  111: 	 */
  112: 	if ((tmpenv = strdup(env)) == NULL)
  113: 		return (errno);
  114: 
  115: 	envvar = strtok_r(tmpenv, ",", &envsave);
  116: 	while (envvar != NULL) {
  117: 		if ((*callback)(envlist, envvar) != 0) {
  118: 			free(tmpenv);
  119: 			return (errno);
  120: 		}
  121: 		envvar = strtok_r(NULL, ",", &envsave);
  122: 	}
  123: 
  124: 	free(tmpenv);
  125: 	return (0);
  126: }
  127: 
  128: /*
  129:  * Sets environment value to envlist in similar manner
  130:  * than putenv(3).
  131:  *
  132:  * Returns 0 in success, errno otherwise.
  133:  */
  134: int
  135: envlist_setenv(envlist_t *envlist, const char *env)
  136: {
  137: 	struct envlist_entry *entry = NULL;
  138: 	const char *eq_sign;
  139: 	size_t envname_len;
  140: 
  141: 	if ((envlist == NULL) || (env == NULL))
  142: 		return (EINVAL);
  143: 
  144: 	/* find out first equals sign in given env */
  145: 	if ((eq_sign = strchr(env, '=')) == NULL)
  146: 		return (EINVAL);
  147: 	envname_len = eq_sign - env + 1;
  148: 
  149: 	/*
  150: 	 * If there already exists variable with given name
  151: 	 * we remove and release it before allocating a whole
  152: 	 * new entry.
  153: 	 */
  154: 	for (entry = envlist->el_entries.lh_first; entry != NULL;
  155: 	    entry = entry->ev_link.le_next) {
  156: 		if (strncmp(entry->ev_var, env, envname_len) == 0)
  157: 			break;
  158: 	}
  159: 
  160: 	if (entry != NULL) {
  161: 		QLIST_REMOVE(entry, ev_link);
  162: 		free((char *)entry->ev_var);
  163: 		free(entry);
  164: 	} else {
  165: 		envlist->el_count++;
  166: 	}
  167: 
  168: 	if ((entry = malloc(sizeof (*entry))) == NULL)
  169: 		return (errno);
  170: 	if ((entry->ev_var = strdup(env)) == NULL) {
  171: 		free(entry);
  172: 		return (errno);
  173: 	}
  174: 	QLIST_INSERT_HEAD(&envlist->el_entries, entry, ev_link);
  175: 
  176: 	return (0);
  177: }
  178: 
  179: /*
  180:  * Removes given env value from envlist in similar manner
  181:  * than unsetenv(3).  Returns 0 in success, errno otherwise.
  182:  */
  183: int
  184: envlist_unsetenv(envlist_t *envlist, const char *env)
  185: {
  186: 	struct envlist_entry *entry;
  187: 	size_t envname_len;
  188: 
  189: 	if ((envlist == NULL) || (env == NULL))
  190: 		return (EINVAL);
  191: 
  192: 	/* env is not allowed to contain '=' */
  193: 	if (strchr(env, '=') != NULL)
  194: 		return (EINVAL);
  195: 
  196: 	/*
  197: 	 * Find out the requested entry and remove
  198: 	 * it from the list.
  199: 	 */
  200: 	envname_len = strlen(env);
  201: 	for (entry = envlist->el_entries.lh_first; entry != NULL;
  202: 	    entry = entry->ev_link.le_next) {
  203: 		if (strncmp(entry->ev_var, env, envname_len) == 0)
  204: 			break;
  205: 	}
  206: 	if (entry != NULL) {
  207: 		QLIST_REMOVE(entry, ev_link);
  208: 		free((char *)entry->ev_var);
  209: 		free(entry);
  210: 
  211: 		envlist->el_count--;
  212: 	}
  213: 	return (0);
  214: }
  215: 
  216: /*
  217:  * Returns given envlist as array of strings (in same form that
  218:  * global variable environ is).  Caller must free returned memory
  219:  * by calling free(3) for each element and for the array.  Returned
  220:  * array and given envlist are not related (no common references).
  221:  *
  222:  * If caller provides count pointer, number of items in array is
  223:  * stored there.  In case of error, NULL is returned and no memory
  224:  * is allocated.
  225:  */
  226: char **
  227: envlist_to_environ(const envlist_t *envlist, size_t *count)
  228: {
  229: 	struct envlist_entry *entry;
  230: 	char **env, **penv;
  231: 
  232: 	penv = env = malloc((envlist->el_count + 1) * sizeof (char *));
  233: 	if (env == NULL)
  234: 		return (NULL);
  235: 
  236: 	for (entry = envlist->el_entries.lh_first; entry != NULL;
  237: 	    entry = entry->ev_link.le_next) {
  238: 		*(penv++) = strdup(entry->ev_var);
  239: 	}
  240: 	*penv = NULL; /* NULL terminate the list */
  241: 
  242: 	if (count != NULL)
  243: 		*count = envlist->el_count;
  244: 
  245: 	return (env);
  246: }

unix.superglobalmegacorp.com