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