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