1 | // SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. |
2 | // |
3 | // SPDX-License-Identifier: GPL-3.0-or-later |
4 | |
5 | #include "config.h" |
6 | #include <string.h> |
7 | |
8 | /*third party lib*/ |
9 | #include <json-c/json.h> |
10 | |
11 | |
12 | static char *alloc_json_string(struct json_object *o) |
13 | { |
14 | const char *v; |
15 | |
16 | if (!json_object_is_type(o, json_type_string)) |
17 | return NULL; |
18 | |
19 | v = json_object_get_string(o); |
20 | if (!v) |
21 | return NULL; |
22 | |
23 | return strdup(v); |
24 | } |
25 | |
26 | static int get_json_int(struct json_object *o, int *i, bool nonneg) |
27 | { |
28 | if (!json_object_is_type(o, json_type_int)) |
29 | return -1; |
30 | |
31 | *i = json_object_get_int(o); |
32 | |
33 | if (*i == INT32_MIN) |
34 | return -1; |
35 | |
36 | if (*i == INT32_MAX) |
37 | return -1; |
38 | |
39 | if (nonneg && *i < 0) |
40 | return -1; |
41 | |
42 | return 0; |
43 | } |
44 | |
45 | static int get_json_boolean(struct json_object *o, bool *b) |
46 | { |
47 | if (!json_object_is_type(o, json_type_boolean)) |
48 | return -1; |
49 | |
50 | *b = json_object_get_boolean(o); |
51 | |
52 | return 0; |
53 | } |
54 | |
55 | static int read_map_config(struct json_object *root, DumpConfig& cfg) |
56 | { |
57 | if (!json_object_is_type(root, json_type_array)) |
58 | return -1; |
59 | |
60 | int len = json_object_array_length(root); |
61 | if (len < 1) |
62 | return -1; |
63 | |
64 | for (int i = 0; i < len; i++) { |
65 | struct json_object *v = json_object_array_get_idx(root, i); |
66 | if (!v) |
67 | return -1; |
68 | |
69 | cfg.modules.push_back(alloc_json_string(v)); |
70 | } |
71 | |
72 | return 0; |
73 | } |
74 | |
75 | static int read_variable_item(struct json_object *root, DumpConfig& cfg) |
76 | { |
77 | struct json_object_iterator it; |
78 | struct json_object_iterator it_end; |
79 | Variable tmp; |
80 | |
81 | tmp.max_size = 1024; |
82 | tmp.is_pointer = false; |
83 | |
84 | for (it = json_object_iter_begin(root), |
85 | it_end = json_object_iter_end(root); |
86 | !json_object_iter_equal(&it, &it_end); |
87 | json_object_iter_next(&it)) { |
88 | |
89 | struct json_object *v; |
90 | const char* n = json_object_iter_peek_name(&it); |
91 | if (!n) |
92 | goto out_err; |
93 | |
94 | v = json_object_iter_peek_value(&it); |
95 | if (!v) |
96 | goto out_err; |
97 | |
98 | if (strcmp(n, "name" ) == 0) { |
99 | tmp.sym_name = alloc_json_string(v); |
100 | if (tmp.sym_name.empty()) |
101 | goto out_err; |
102 | } |
103 | else if (strcmp(n, "is_pointer" ) == 0) { |
104 | get_json_boolean(v, &tmp.is_pointer); |
105 | } |
106 | else if (strcmp(n, "max_size" ) == 0) { |
107 | int number = 0; |
108 | get_json_int(v, &number, true); |
109 | if (number > 0) { |
110 | tmp.max_size = (number + 3) & (~3); |
111 | } |
112 | } else { |
113 | printf("WARNING: ignoring unknown config item: %s\n" , n); |
114 | } |
115 | } |
116 | |
117 | cfg.vars.push_back(tmp); |
118 | |
119 | return 0; |
120 | |
121 | out_err: |
122 | return -1; |
123 | } |
124 | |
125 | |
126 | static int read_global_var_config(struct json_object *root, DumpConfig& cfg) |
127 | { |
128 | if (!json_object_is_type(root, json_type_array)) |
129 | return -1; |
130 | |
131 | int len = json_object_array_length(root); |
132 | if (len < 1) |
133 | return -1; |
134 | |
135 | for (int i = 0; i < len; i++) { |
136 | struct json_object *v; |
137 | |
138 | v = json_object_array_get_idx(root, i); |
139 | if (!v) |
140 | return -1; |
141 | |
142 | if (read_variable_item(v, cfg) != 0) |
143 | return -1; |
144 | } |
145 | |
146 | return 0; |
147 | } |
148 | |
149 | int load_config(DumpConfig& cfg) |
150 | { |
151 | const char* user_file = nullptr; |
152 | char cfg_file[256]; |
153 | struct json_object_iterator it; |
154 | struct json_object_iterator it_end; |
155 | |
156 | cfg.max_heap_size = 0; |
157 | cfg.dump_pthread_list = false; |
158 | cfg.dump_robust_mutex_list = false; |
159 | cfg.current_thread_only = false; |
160 | cfg.max_stack_size = 32*1024; /*set zero to disable dump stack*/ |
161 | cfg.max_param_size = 256; |
162 | cfg.compress_level = 3; |
163 | cfg.shared_buffer_size = 4*1024*1024; |
164 | cfg.max_dump_bytes = 4*1024*1024*1024LL; |
165 | |
166 | cfg.log_to_stdout = false; |
167 | cfg.log_to_file = true; |
168 | cfg.log_file_max_size = 20*1024*1024; |
169 | cfg.log_flush_threshold = 0; |
170 | cfg.log_debug = false; |
171 | |
172 | user_file = getenv("ST2_CONFIG_FILE" ); |
173 | if (nullptr == user_file) { |
174 | snprintf(cfg_file, sizeof(cfg_file), "%s/.config/emd.json" , getenv("HOME" )); |
175 | } |
176 | else { |
177 | snprintf(cfg_file, sizeof(cfg_file), "%s" , user_file); |
178 | } |
179 | struct json_object* root = json_object_from_file(cfg_file); |
180 | if (!root) { |
181 | fprintf(stderr, "failed to open or parse :%s, error:%s\n" , |
182 | cfg_file, strerror(errno)); |
183 | goto end; |
184 | } |
185 | |
186 | for (it = json_object_iter_begin(root), |
187 | it_end = json_object_iter_end(root); |
188 | !json_object_iter_equal(&it, &it_end); |
189 | json_object_iter_next(&it)) { |
190 | |
191 | struct json_object *v = nullptr; |
192 | const char* n = json_object_iter_peek_name(&it); |
193 | if (!n) |
194 | break; |
195 | |
196 | v = json_object_iter_peek_value(&it); |
197 | if (!v) |
198 | break; |
199 | |
200 | if (strcmp(n, "dump_dir" ) == 0) { |
201 | cfg.dump_dir = alloc_json_string(v); |
202 | } |
203 | else if (strcmp(n, "modules" ) == 0) { |
204 | read_map_config(v, cfg); |
205 | } |
206 | else if (strcmp(n, "variables" ) == 0) { |
207 | read_global_var_config(v, cfg); |
208 | } |
209 | else if (strcmp(n, "compress_level" ) == 0) { |
210 | get_json_int(v, &cfg.compress_level, true); |
211 | } |
212 | else if (strcmp(n, "dump_pthread_list" ) == 0) { |
213 | get_json_boolean(v, &cfg.dump_pthread_list); |
214 | } |
215 | else if (strcmp(n, "dump_robust_mutex_list" ) == 0) { |
216 | get_json_boolean(v, &cfg.dump_robust_mutex_list); |
217 | } |
218 | else if (strcmp(n, "log_debug" ) == 0) { |
219 | get_json_boolean(v, &cfg.log_debug); |
220 | } |
221 | else if (strcmp(n, "log_to_stdout" ) == 0) { |
222 | get_json_boolean(v, &cfg.log_to_stdout); |
223 | } |
224 | else if (strcmp(n, "log_to_file" ) == 0) { |
225 | get_json_boolean(v, &cfg.log_to_file); |
226 | } |
227 | else if (strcmp(n, "shared_buffer_size" ) == 0) { |
228 | int number = 0; |
229 | get_json_int(v, &number, true); |
230 | if (number > 0) { |
231 | cfg.shared_buffer_size = number*1024; |
232 | } |
233 | } |
234 | else if (strcmp(n, "max_dump_bytes" ) == 0) { |
235 | int number = 0; |
236 | get_json_int(v, &number, true); |
237 | if (number > 0) { |
238 | cfg.max_dump_bytes = number*1024LL; |
239 | } |
240 | } |
241 | else if (strcmp(n, "log_file_max_size" ) == 0) { |
242 | int number = 0; |
243 | get_json_int(v, &number, true); |
244 | if (number > 0) { |
245 | cfg.log_file_max_size = number*1024; |
246 | } |
247 | } |
248 | else if (strcmp(n, "log_flush_threshold" ) == 0) { |
249 | int number = 0; |
250 | get_json_int(v, &number, true); |
251 | if (number >= 0) { |
252 | cfg.log_flush_threshold = number*1024; |
253 | } |
254 | } |
255 | else if (strcmp(n, "mode" ) == 0) { |
256 | get_json_int(v, (int*)&cfg.mode, true); |
257 | } |
258 | else { |
259 | printf("WARNING: ignoring unknown config item: %s\n" , n); |
260 | } |
261 | } |
262 | |
263 | json_object_put(root); |
264 | |
265 | end: |
266 | if (cfg.dump_dir.empty()) { |
267 | cfg.dump_dir = getenv("HOME" ); |
268 | cfg.dump_dir += "/.local/share/emd/" ; |
269 | } |
270 | else if (cfg.dump_dir[0] == '~') { |
271 | cfg.dump_dir.replace(0, 1, getenv("HOME" )); |
272 | } |
273 | |
274 | return 0; |
275 | } |
276 | |
277 | |
278 | |