Statistics
| Branch: | Revision:

root / envlist.c @ 72cf2d4f

History | View | Annotate | Download (5.3 kB)

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