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