1aafd7584SPeter Maydell #include "qemu/osdep.h"
21de7afc9SPaolo Bonzini #include "qemu/queue.h"
31de7afc9SPaolo Bonzini #include "qemu/envlist.h"
404a6dfebSaurel32
504a6dfebSaurel32 struct envlist_entry {
604a6dfebSaurel32 const char *ev_var; /* actual env value */
772cf2d4fSBlue Swirl QLIST_ENTRY(envlist_entry) ev_link;
804a6dfebSaurel32 };
904a6dfebSaurel32
1004a6dfebSaurel32 struct envlist {
1172cf2d4fSBlue Swirl QLIST_HEAD(, envlist_entry) el_entries; /* actual entries */
1204a6dfebSaurel32 size_t el_count; /* number of entries */
1304a6dfebSaurel32 };
1404a6dfebSaurel32
1504a6dfebSaurel32 /*
16ec45bbe5SSaurav Sachidanand * Allocates new envlist and returns pointer to it.
1704a6dfebSaurel32 */
1804a6dfebSaurel32 envlist_t *
envlist_create(void)1904a6dfebSaurel32 envlist_create(void)
2004a6dfebSaurel32 {
2104a6dfebSaurel32 envlist_t *envlist;
2204a6dfebSaurel32
23ec45bbe5SSaurav Sachidanand envlist = g_malloc(sizeof(*envlist));
2404a6dfebSaurel32
2572cf2d4fSBlue Swirl QLIST_INIT(&envlist->el_entries);
2604a6dfebSaurel32 envlist->el_count = 0;
2704a6dfebSaurel32
2804a6dfebSaurel32 return (envlist);
2904a6dfebSaurel32 }
3004a6dfebSaurel32
3104a6dfebSaurel32 /*
3204a6dfebSaurel32 * Releases given envlist and its entries.
3304a6dfebSaurel32 */
3404a6dfebSaurel32 void
envlist_free(envlist_t * envlist)3504a6dfebSaurel32 envlist_free(envlist_t *envlist)
3604a6dfebSaurel32 {
3704a6dfebSaurel32 struct envlist_entry *entry;
3804a6dfebSaurel32
3904a6dfebSaurel32 assert(envlist != NULL);
4004a6dfebSaurel32
4104a6dfebSaurel32 while (envlist->el_entries.lh_first != NULL) {
4204a6dfebSaurel32 entry = envlist->el_entries.lh_first;
4372cf2d4fSBlue Swirl QLIST_REMOVE(entry, ev_link);
4404a6dfebSaurel32
45ec45bbe5SSaurav Sachidanand g_free((char *)entry->ev_var);
46ec45bbe5SSaurav Sachidanand g_free(entry);
4704a6dfebSaurel32 }
48ec45bbe5SSaurav Sachidanand g_free(envlist);
4904a6dfebSaurel32 }
5004a6dfebSaurel32
5104a6dfebSaurel32 /*
5204a6dfebSaurel32 * Sets environment value to envlist in similar manner
5304a6dfebSaurel32 * than putenv(3).
5404a6dfebSaurel32 *
5504a6dfebSaurel32 * Returns 0 in success, errno otherwise.
5604a6dfebSaurel32 */
5704a6dfebSaurel32 int
envlist_setenv(envlist_t * envlist,const char * env)5804a6dfebSaurel32 envlist_setenv(envlist_t *envlist, const char *env)
5904a6dfebSaurel32 {
6004a6dfebSaurel32 struct envlist_entry *entry = NULL;
6104a6dfebSaurel32 const char *eq_sign;
6204a6dfebSaurel32 size_t envname_len;
6304a6dfebSaurel32
6404a6dfebSaurel32 if ((envlist == NULL) || (env == NULL))
6504a6dfebSaurel32 return (EINVAL);
6604a6dfebSaurel32
6704a6dfebSaurel32 /* find out first equals sign in given env */
6804a6dfebSaurel32 if ((eq_sign = strchr(env, '=')) == NULL)
6904a6dfebSaurel32 return (EINVAL);
7004a6dfebSaurel32 envname_len = eq_sign - env + 1;
7104a6dfebSaurel32
7204a6dfebSaurel32 /*
7304a6dfebSaurel32 * If there already exists variable with given name
7404a6dfebSaurel32 * we remove and release it before allocating a whole
7504a6dfebSaurel32 * new entry.
7604a6dfebSaurel32 */
7704a6dfebSaurel32 for (entry = envlist->el_entries.lh_first; entry != NULL;
7804a6dfebSaurel32 entry = entry->ev_link.le_next) {
7904a6dfebSaurel32 if (strncmp(entry->ev_var, env, envname_len) == 0)
8004a6dfebSaurel32 break;
8104a6dfebSaurel32 }
8204a6dfebSaurel32
8304a6dfebSaurel32 if (entry != NULL) {
8472cf2d4fSBlue Swirl QLIST_REMOVE(entry, ev_link);
85ec45bbe5SSaurav Sachidanand g_free((char *)entry->ev_var);
86ec45bbe5SSaurav Sachidanand g_free(entry);
8704a6dfebSaurel32 } else {
8804a6dfebSaurel32 envlist->el_count++;
8904a6dfebSaurel32 }
9004a6dfebSaurel32
91ec45bbe5SSaurav Sachidanand entry = g_malloc(sizeof(*entry));
92ec45bbe5SSaurav Sachidanand entry->ev_var = g_strdup(env);
9372cf2d4fSBlue Swirl QLIST_INSERT_HEAD(&envlist->el_entries, entry, ev_link);
9404a6dfebSaurel32
9504a6dfebSaurel32 return (0);
9604a6dfebSaurel32 }
9704a6dfebSaurel32
9804a6dfebSaurel32 /*
9904a6dfebSaurel32 * Removes given env value from envlist in similar manner
10004a6dfebSaurel32 * than unsetenv(3). Returns 0 in success, errno otherwise.
10104a6dfebSaurel32 */
10204a6dfebSaurel32 int
envlist_unsetenv(envlist_t * envlist,const char * env)10304a6dfebSaurel32 envlist_unsetenv(envlist_t *envlist, const char *env)
10404a6dfebSaurel32 {
10504a6dfebSaurel32 struct envlist_entry *entry;
10604a6dfebSaurel32 size_t envname_len;
10704a6dfebSaurel32
10804a6dfebSaurel32 if ((envlist == NULL) || (env == NULL))
10904a6dfebSaurel32 return (EINVAL);
11004a6dfebSaurel32
11104a6dfebSaurel32 /* env is not allowed to contain '=' */
11204a6dfebSaurel32 if (strchr(env, '=') != NULL)
11304a6dfebSaurel32 return (EINVAL);
11404a6dfebSaurel32
11504a6dfebSaurel32 /*
11604a6dfebSaurel32 * Find out the requested entry and remove
11704a6dfebSaurel32 * it from the list.
11804a6dfebSaurel32 */
11904a6dfebSaurel32 envname_len = strlen(env);
12004a6dfebSaurel32 for (entry = envlist->el_entries.lh_first; entry != NULL;
12104a6dfebSaurel32 entry = entry->ev_link.le_next) {
12204a6dfebSaurel32 if (strncmp(entry->ev_var, env, envname_len) == 0)
12304a6dfebSaurel32 break;
12404a6dfebSaurel32 }
12504a6dfebSaurel32 if (entry != NULL) {
12672cf2d4fSBlue Swirl QLIST_REMOVE(entry, ev_link);
127ec45bbe5SSaurav Sachidanand g_free((char *)entry->ev_var);
128ec45bbe5SSaurav Sachidanand g_free(entry);
12904a6dfebSaurel32
13004a6dfebSaurel32 envlist->el_count--;
13104a6dfebSaurel32 }
13204a6dfebSaurel32 return (0);
13304a6dfebSaurel32 }
13404a6dfebSaurel32
13504a6dfebSaurel32 /*
13604a6dfebSaurel32 * Returns given envlist as array of strings (in same form that
13704a6dfebSaurel32 * 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).
14104a6dfebSaurel32 *
14204a6dfebSaurel32 * If caller provides count pointer, number of items in array is
143ec45bbe5SSaurav Sachidanand * stored there.
14404a6dfebSaurel32 */
14504a6dfebSaurel32 char **
envlist_to_environ(const envlist_t * envlist,size_t * count)14604a6dfebSaurel32 envlist_to_environ(const envlist_t *envlist, size_t *count)
14704a6dfebSaurel32 {
14804a6dfebSaurel32 struct envlist_entry *entry;
14904a6dfebSaurel32 char **env, **penv;
15004a6dfebSaurel32
151*b21e2380SMarkus Armbruster penv = env = g_new(char *, envlist->el_count + 1);
15204a6dfebSaurel32
15304a6dfebSaurel32 for (entry = envlist->el_entries.lh_first; entry != NULL;
15404a6dfebSaurel32 entry = entry->ev_link.le_next) {
155ec45bbe5SSaurav Sachidanand *(penv++) = g_strdup(entry->ev_var);
15604a6dfebSaurel32 }
15704a6dfebSaurel32 *penv = NULL; /* NULL terminate the list */
15804a6dfebSaurel32
15904a6dfebSaurel32 if (count != NULL)
16004a6dfebSaurel32 *count = envlist->el_count;
16104a6dfebSaurel32
16204a6dfebSaurel32 return (env);
16304a6dfebSaurel32 }
164