2
0

envlist.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. #include "qemu/osdep.h"
  2. #include "qemu/queue.h"
  3. #include "qemu/envlist.h"
  4. struct envlist_entry {
  5. const char *ev_var; /* actual env value */
  6. QLIST_ENTRY(envlist_entry) ev_link;
  7. };
  8. struct envlist {
  9. QLIST_HEAD(, envlist_entry) el_entries; /* actual entries */
  10. size_t el_count; /* number of entries */
  11. };
  12. static int envlist_parse(envlist_t *envlist,
  13. const char *env, int (*)(envlist_t *, const char *));
  14. /*
  15. * Allocates new envlist and returns pointer to it.
  16. */
  17. envlist_t *
  18. envlist_create(void)
  19. {
  20. envlist_t *envlist;
  21. envlist = g_malloc(sizeof(*envlist));
  22. QLIST_INIT(&envlist->el_entries);
  23. envlist->el_count = 0;
  24. return (envlist);
  25. }
  26. /*
  27. * Releases given envlist and its entries.
  28. */
  29. void
  30. envlist_free(envlist_t *envlist)
  31. {
  32. struct envlist_entry *entry;
  33. assert(envlist != NULL);
  34. while (envlist->el_entries.lh_first != NULL) {
  35. entry = envlist->el_entries.lh_first;
  36. QLIST_REMOVE(entry, ev_link);
  37. g_free((char *)entry->ev_var);
  38. g_free(entry);
  39. }
  40. g_free(envlist);
  41. }
  42. /*
  43. * Parses comma separated list of set/modify environment
  44. * variable entries and updates given enlist accordingly.
  45. *
  46. * For example:
  47. * envlist_parse(el, "HOME=foo,SHELL=/bin/sh");
  48. *
  49. * inserts/sets environment variables HOME and SHELL.
  50. *
  51. * Returns 0 on success, errno otherwise.
  52. */
  53. int
  54. envlist_parse_set(envlist_t *envlist, const char *env)
  55. {
  56. return (envlist_parse(envlist, env, &envlist_setenv));
  57. }
  58. /*
  59. * Parses comma separated list of unset environment variable
  60. * entries and removes given variables from given envlist.
  61. *
  62. * Returns 0 on success, errno otherwise.
  63. */
  64. int
  65. envlist_parse_unset(envlist_t *envlist, const char *env)
  66. {
  67. return (envlist_parse(envlist, env, &envlist_unsetenv));
  68. }
  69. /*
  70. * Parses comma separated list of set, modify or unset entries
  71. * and calls given callback for each entry.
  72. *
  73. * Returns 0 in case of success, errno otherwise.
  74. */
  75. static int
  76. envlist_parse(envlist_t *envlist, const char *env,
  77. int (*callback)(envlist_t *, const char *))
  78. {
  79. char *tmpenv, *envvar;
  80. char *envsave = NULL;
  81. int ret = 0;
  82. assert(callback != NULL);
  83. if ((envlist == NULL) || (env == NULL))
  84. return (EINVAL);
  85. tmpenv = g_strdup(env);
  86. envsave = tmpenv;
  87. do {
  88. envvar = strchr(tmpenv, ',');
  89. if (envvar != NULL) {
  90. *envvar = '\0';
  91. }
  92. if ((*callback)(envlist, tmpenv) != 0) {
  93. ret = errno;
  94. break;
  95. }
  96. tmpenv = envvar + 1;
  97. } while (envvar != NULL);
  98. g_free(envsave);
  99. return ret;
  100. }
  101. /*
  102. * Sets environment value to envlist in similar manner
  103. * than putenv(3).
  104. *
  105. * Returns 0 in success, errno otherwise.
  106. */
  107. int
  108. envlist_setenv(envlist_t *envlist, const char *env)
  109. {
  110. struct envlist_entry *entry = NULL;
  111. const char *eq_sign;
  112. size_t envname_len;
  113. if ((envlist == NULL) || (env == NULL))
  114. return (EINVAL);
  115. /* find out first equals sign in given env */
  116. if ((eq_sign = strchr(env, '=')) == NULL)
  117. return (EINVAL);
  118. envname_len = eq_sign - env + 1;
  119. /*
  120. * If there already exists variable with given name
  121. * we remove and release it before allocating a whole
  122. * new entry.
  123. */
  124. for (entry = envlist->el_entries.lh_first; entry != NULL;
  125. entry = entry->ev_link.le_next) {
  126. if (strncmp(entry->ev_var, env, envname_len) == 0)
  127. break;
  128. }
  129. if (entry != NULL) {
  130. QLIST_REMOVE(entry, ev_link);
  131. g_free((char *)entry->ev_var);
  132. g_free(entry);
  133. } else {
  134. envlist->el_count++;
  135. }
  136. entry = g_malloc(sizeof(*entry));
  137. entry->ev_var = g_strdup(env);
  138. QLIST_INSERT_HEAD(&envlist->el_entries, entry, ev_link);
  139. return (0);
  140. }
  141. /*
  142. * Removes given env value from envlist in similar manner
  143. * than unsetenv(3). Returns 0 in success, errno otherwise.
  144. */
  145. int
  146. envlist_unsetenv(envlist_t *envlist, const char *env)
  147. {
  148. struct envlist_entry *entry;
  149. size_t envname_len;
  150. if ((envlist == NULL) || (env == NULL))
  151. return (EINVAL);
  152. /* env is not allowed to contain '=' */
  153. if (strchr(env, '=') != NULL)
  154. return (EINVAL);
  155. /*
  156. * Find out the requested entry and remove
  157. * it from the list.
  158. */
  159. envname_len = strlen(env);
  160. for (entry = envlist->el_entries.lh_first; entry != NULL;
  161. entry = entry->ev_link.le_next) {
  162. if (strncmp(entry->ev_var, env, envname_len) == 0)
  163. break;
  164. }
  165. if (entry != NULL) {
  166. QLIST_REMOVE(entry, ev_link);
  167. g_free((char *)entry->ev_var);
  168. g_free(entry);
  169. envlist->el_count--;
  170. }
  171. return (0);
  172. }
  173. /*
  174. * Returns given envlist as array of strings (in same form that
  175. * global variable environ is). Caller must free returned memory
  176. * by calling g_free for each element and the array.
  177. * Returned array and given envlist are not related (no common
  178. * references).
  179. *
  180. * If caller provides count pointer, number of items in array is
  181. * stored there.
  182. */
  183. char **
  184. envlist_to_environ(const envlist_t *envlist, size_t *count)
  185. {
  186. struct envlist_entry *entry;
  187. char **env, **penv;
  188. penv = env = g_malloc((envlist->el_count + 1) * sizeof(char *));
  189. for (entry = envlist->el_entries.lh_first; entry != NULL;
  190. entry = entry->ev_link.le_next) {
  191. *(penv++) = g_strdup(entry->ev_var);
  192. }
  193. *penv = NULL; /* NULL terminate the list */
  194. if (count != NULL)
  195. *count = envlist->el_count;
  196. return (env);
  197. }