xref: /openbmc/qemu/util/envlist.c (revision 2e1cacfb)
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 *
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
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
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
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 **
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