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