master
c 174 lines 4.16 KB
Raw
1 #include "qemu/osdep.h"
2 #include "qemu/queue.h"
3 #include "qemu/envlist.h"
4
5 struct envlist_entry {
6 const char *ev_var; /* actual env value: "NAME=VALUE" */
7 size_t ev_name_len; /* length of NAME (offset of '=') */
8 QLIST_ENTRY(envlist_entry) ev_link;
9 };
10
11 struct envlist {
12 QLIST_HEAD(, envlist_entry) el_entries; /* actual entries */
13 size_t el_count; /* number of entries */
14 };
15
16 static inline bool envlist_name_eq(const struct envlist_entry *entry,
17 const char *name, size_t name_len)
18 {
19 return entry->ev_name_len == name_len &&
20 memcmp(entry->ev_var, name, name_len) == 0;
21 }
22
23 /*
24 * Allocates new envlist and returns pointer to it.
25 */
26 envlist_t *
27 envlist_create(void)
28 {
29 envlist_t *envlist;
30
31 envlist = g_malloc(sizeof(*envlist));
32
33 QLIST_INIT(&envlist->el_entries);
34 envlist->el_count = 0;
35
36 return (envlist);
37 }
38
39 /*
40 * Releases given envlist and its entries.
41 */
42 void
43 envlist_free(envlist_t *envlist)
44 {
45 struct envlist_entry *entry;
46
47 assert(envlist != NULL);
48
49 while (envlist->el_entries.lh_first != NULL) {
50 entry = envlist->el_entries.lh_first;
51 QLIST_REMOVE(entry, ev_link);
52
53 g_free((char *)entry->ev_var);
54 g_free(entry);
55 }
56 g_free(envlist);
57 }
58
59 /*
60 * Sets environment value to envlist in similar manner
61 * than putenv(3).
62 *
63 * Returns 0 in success, errno otherwise.
64 */
65 int
66 envlist_setenv(envlist_t *envlist, const char *env)
67 {
68 struct envlist_entry *entry = NULL;
69 const char *eq_sign;
70 size_t envname_len;
71
72 if ((envlist == NULL) || (env == NULL))
73 return (EINVAL);
74
75 /* find out first equals sign in given env */
76 if ((eq_sign = strchr(env, '=')) == NULL)
77 return (EINVAL);
78 envname_len = eq_sign - env;
79
80 /*
81 * If there already exists variable with given name
82 * we remove and release it before allocating a whole
83 * new entry.
84 */
85 for (entry = envlist->el_entries.lh_first; entry != NULL;
86 entry = entry->ev_link.le_next) {
87 if (envlist_name_eq(entry, env, envname_len)) {
88 break;
89 }
90 }
91
92 if (entry != NULL) {
93 QLIST_REMOVE(entry, ev_link);
94 g_free((char *)entry->ev_var);
95 g_free(entry);
96 } else {
97 envlist->el_count++;
98 }
99
100 entry = g_malloc(sizeof(*entry));
101 entry->ev_var = g_strdup(env);
102 entry->ev_name_len = envname_len;
103 QLIST_INSERT_HEAD(&envlist->el_entries, entry, ev_link);
104
105 return (0);
106 }
107
108 /*
109 * Removes given env value from envlist in similar manner
110 * than unsetenv(3). Returns 0 in success, errno otherwise.
111 */
112 int
113 envlist_unsetenv(envlist_t *envlist, const char *env)
114 {
115 struct envlist_entry *entry;
116 size_t envname_len;
117
118 if ((envlist == NULL) || (env == NULL))
119 return (EINVAL);
120
121 /* env is not allowed to contain '=' */
122 if (strchr(env, '=') != NULL)
123 return (EINVAL);
124
125 /*
126 * Find out the requested entry and remove
127 * it from the list.
128 */
129 envname_len = strlen(env);
130 for (entry = envlist->el_entries.lh_first; entry != NULL;
131 entry = entry->ev_link.le_next) {
132 if (envlist_name_eq(entry, env, envname_len)) {
133 break;
134 }
135 }
136 if (entry != NULL) {
137 QLIST_REMOVE(entry, ev_link);
138 g_free((char *)entry->ev_var);
139 g_free(entry);
140
141 envlist->el_count--;
142 }
143 return (0);
144 }
145
146 /*
147 * Returns given envlist as array of strings (in same form that
148 * global variable environ is). Caller must free returned memory
149 * by calling g_free for each element and the array.
150 * Returned array and given envlist are not related (no common
151 * references).
152 *
153 * If caller provides count pointer, number of items in array is
154 * stored there.
155 */
156 char **
157 envlist_to_environ(const envlist_t *envlist, size_t *count)
158 {
159 struct envlist_entry *entry;
160 char **env, **penv;
161
162 penv = env = g_new(char *, envlist->el_count + 1);
163
164 for (entry = envlist->el_entries.lh_first; entry != NULL;
165 entry = entry->ev_link.le_next) {
166 *(penv++) = g_strdup(entry->ev_var);
167 }
168 *penv = NULL; /* NULL terminate the list */
169
170 if (count != NULL)
171 *count = envlist->el_count;
172
173 return (env);
174 }