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