1 /* Copyright 2014-present Facebook, Inc.
2 * Licensed under the Apache License, Version 2.0 */
3
4 #include "watchman.h"
5
6 /* Constructs a hash table from the current process environment */
w_envp_make_ht(void)7 w_ht_t *w_envp_make_ht(void)
8 {
9 w_ht_t *ht;
10 uint32_t nenv, i;
11 const char *eq;
12 const char *ent;
13 w_string_t *key, *val, *str;
14
15 for (i = 0, nenv = 0; environ[i]; i++) {
16 nenv++;
17 }
18
19 ht = w_ht_new(nenv, &w_ht_dict_funcs);
20
21 for (i = 0; environ[i]; i++) {
22 ent = environ[i];
23 eq = strchr(ent, '=');
24 if (!eq) {
25 continue;
26 }
27
28 // slice name=value into a key and a value string
29 str = w_string_new(ent);
30 key = w_string_slice(str, 0, (uint32_t)(eq - ent));
31 val = w_string_slice(str, 1 + (uint32_t)(eq - ent),
32 (uint32_t)(str->len - (key->len + 1)));
33
34 // Replace rather than set, just in case we somehow have duplicate
35 // keys in our environment array.
36 w_ht_replace(ht, w_ht_ptr_val(key), w_ht_ptr_val(val));
37
38 // Release our slices
39 w_string_delref(str);
40 w_string_delref(key);
41 w_string_delref(val);
42 }
43
44 return ht;
45 }
46
47 /* Constructs an envp array from a hash table.
48 * The returned array occupies a single contiguous block of memory
49 * such that it can be released by a single call to free(3).
50 * The last element of the returned array is set to NULL for compatibility
51 * with posix_spawn() */
w_envp_make_from_ht(w_ht_t * ht,uint32_t * env_size)52 char **w_envp_make_from_ht(w_ht_t *ht, uint32_t *env_size)
53 {
54 int nele = w_ht_size(ht);
55 int len = (1 + nele) * sizeof(char*);
56 w_ht_iter_t iter;
57 char **envp;
58 char *buf;
59 uint32_t i = 0;
60
61 // Make a pass through to compute the required memory size
62 if (w_ht_first(ht, &iter)) do {
63 w_string_t *key = w_ht_val_ptr(iter.key);
64 w_string_t *val = w_ht_val_ptr(iter.value);
65
66 // key=value\0
67 len += key->len + 1 + val->len + 1;
68 } while (w_ht_next(ht, &iter));
69
70 *env_size = len;
71
72 envp = malloc(len);
73 if (!envp) {
74 return NULL;
75 }
76
77 buf = (char*)(envp + nele + 1);
78
79 // Now populate
80 if (w_ht_first(ht, &iter)) do {
81 w_string_t *key = w_ht_val_ptr(iter.key);
82 w_string_t *val = w_ht_val_ptr(iter.value);
83
84 envp[i++] = buf;
85
86 // key=value\0
87 memcpy(buf, key->buf, key->len);
88 buf += key->len;
89
90 memcpy(buf, "=", 1);
91 buf++;
92
93 memcpy(buf, val->buf, val->len);
94 buf += val->len;
95
96 *buf = 0;
97 buf++;
98 } while (w_ht_next(ht, &iter));
99
100 envp[nele] = NULL;
101
102 return envp;
103 }
104
w_envp_set_bool(w_ht_t * envht,const char * key,bool val)105 void w_envp_set_bool(w_ht_t *envht, const char *key, bool val)
106 {
107 if (val) {
108 w_envp_set_cstring(envht, key, "true");
109 } else {
110 w_envp_unset(envht, key);
111 }
112 }
113
w_envp_unset(w_ht_t * envht,const char * key)114 void w_envp_unset(w_ht_t *envht, const char *key)
115 {
116 w_string_t *kstr = w_string_new(key);
117
118 w_ht_del(envht, w_ht_ptr_val(kstr));
119
120 w_string_delref(kstr);
121 }
122
w_envp_set(w_ht_t * envht,const char * key,w_string_t * val)123 void w_envp_set(w_ht_t *envht, const char *key, w_string_t *val)
124 {
125 w_string_t *kstr = w_string_new(key);
126
127 w_ht_replace(envht, w_ht_ptr_val(kstr), w_ht_ptr_val(val));
128
129 w_string_delref(kstr);
130 }
131
w_envp_set_cstring(w_ht_t * envht,const char * key,const char * val)132 void w_envp_set_cstring(w_ht_t *envht, const char *key, const char *val)
133 {
134 w_string_t *kstr = w_string_new(key);
135 w_string_t *vstr = w_string_new(val);
136
137 w_ht_replace(envht, w_ht_ptr_val(kstr), w_ht_ptr_val(vstr));
138
139 w_string_delref(kstr);
140 w_string_delref(vstr);
141 }
142
143 /* vim:ts=2:sw=2:et:
144 */
145