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