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