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