xref: /qemu/util/envlist.c (revision a53b931645183bd0c15dd19ae0708fc3c81ecf1d)
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