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