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