d4385738fd3d37c2c287677718adc4a201389862
[lttng-tools.git] / src / common / config / config.c
1 /*
2 * Copyright (C) 2013 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License, version 2 only, as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 51
15 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18 #define _GNU_SOURCE
19 #include <assert.h>
20 #include <ctype.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <inttypes.h>
25
26 #include <common/defaults.h>
27 #include <common/error.h>
28 #include <common/macros.h>
29 #include <common/utils.h>
30 #include <common/config/config-session-internal.h>
31 #include <lttng/lttng-error.h>
32 #include <libxml/parser.h>
33 #include <libxml/valid.h>
34 #include <libxml/xmlschemas.h>
35
36 #include "config.h"
37 #include "config-internal.h"
38
39 struct handler_filter_args {
40 const char* section;
41 config_entry_handler_cb handler;
42 void *user_data;
43 };
44
45 const char * const config_str_yes = "yes";
46 const char * const config_str_true = "true";
47 const char * const config_str_on = "on";
48 const char * const config_str_no = "no";
49 const char * const config_str_false = "false";
50 const char * const config_str_off = "off";
51 const char * const config_xml_encoding = "UTF-8";
52 const size_t config_xml_encoding_bytes_per_char = 2; /* Size of the encoding's largest character */
53 const char * const config_xml_indent_string = "\t";
54 const char * const config_xml_true = "true";
55 const char * const config_xml_false = "false";
56
57 const char * const config_element_channel = "channel";
58 const char * const config_element_channels = "channels";
59 const char * const config_element_domain = "domain";
60 const char * const config_element_domains = "domains";
61 const char * const config_element_event = "event";
62 const char * const config_element_events = "events";
63 const char * const config_element_context = "context";
64 const char * const config_element_contexts = "contexts";
65 const char * const config_element_attributes = "attributes";
66 const char * const config_element_exclusion = "exclusion";
67 const char * const config_element_exclusions = "exclusions";
68 const char * const config_element_function_attributes = "function_attributes";
69 const char * const config_element_probe_attributes = "probe_attributes";
70 const char * const config_element_symbol_name = "symbol_name";
71 const char * const config_element_address = "address";
72 const char * const config_element_offset = "offset";
73 const char * const config_element_name = "name";
74 const char * const config_element_enabled = "enabled";
75 const char * const config_element_overwrite_mode = "overwrite_mode";
76 const char * const config_element_subbuf_size = "subbuffer_size";
77 const char * const config_element_num_subbuf = "subbuffer_count";
78 const char * const config_element_switch_timer_interval = "switch_timer_interval";
79 const char * const config_element_read_timer_interval = "read_timer_interval";
80 const char * const config_element_output = "output";
81 const char * const config_element_output_type = "output_type";
82 const char * const config_element_tracefile_size = "tracefile_size";
83 const char * const config_element_tracefile_count = "tracefile_count";
84 const char * const config_element_live_timer_interval = "live_timer_interval";
85 const char * const config_element_type = "type";
86 const char * const config_element_buffer_type = "buffer_type";
87 const char * const config_element_session = "session";
88 const char * const config_element_sessions = "sessions";
89 const char * const config_element_perf = "perf";
90 const char * const config_element_config = "config";
91 const char * const config_element_started = "started";
92 const char * const config_element_snapshot_mode = "snapshot_mode";
93 const char * const config_element_loglevel = "loglevel";
94 const char * const config_element_loglevel_type = "loglevel_type";
95 const char * const config_element_filter = "filter";
96 const char * const config_element_snapshot_outputs = "snapshot_outputs";
97 const char * const config_element_consumer_output = "consumer_output";
98 const char * const config_element_destination = "destination";
99 const char * const config_element_path = "path";
100 const char * const config_element_net_output = "net_output";
101 const char * const config_element_control_uri = "control_uri";
102 const char * const config_element_data_uri = "data_uri";
103 const char * const config_element_max_size = "max_size";
104
105 const char * const config_domain_type_kernel = "KERNEL";
106 const char * const config_domain_type_ust = "UST";
107 const char * const config_domain_type_jul = "JUL";
108
109 const char * const config_buffer_type_per_pid = "PER_PID";
110 const char * const config_buffer_type_per_uid = "PER_UID";
111 const char * const config_buffer_type_global = "GLOBAL";
112
113 const char * const config_overwrite_mode_discard = "DISCARD";
114 const char * const config_overwrite_mode_overwrite = "OVERWRITE";
115
116 const char * const config_output_type_splice = "SPLICE";
117 const char * const config_output_type_mmap = "MMAP";
118
119 const char * const config_loglevel_type_all = "ALL";
120 const char * const config_loglevel_type_range = "RANGE";
121 const char * const config_loglevel_type_single = "SINGLE";
122
123 const char * const config_event_type_all = "ALL";
124 const char * const config_event_type_tracepoint = "TRACEPOINT";
125 const char * const config_event_type_probe = "PROBE";
126 const char * const config_event_type_function = "FUNCTION";
127 const char * const config_event_type_function_entry = "FUNCTION_ENTRY";
128 const char * const config_event_type_noop = "NOOP";
129 const char * const config_event_type_syscall = "SYSCALL";
130 const char * const config_event_type_kprobe = "KPROBE";
131 const char * const config_event_type_kretprobe = "KRETPROBE";
132
133 const char * const config_event_context_pid = "PID";
134 const char * const config_event_context_procname = "PROCNAME";
135 const char * const config_event_context_prio = "PRIO";
136 const char * const config_event_context_nice = "NICE";
137 const char * const config_event_context_vpid = "VPID";
138 const char * const config_event_context_tid = "TID";
139 const char * const config_event_context_vtid = "VTID";
140 const char * const config_event_context_ppid = "PPID";
141 const char * const config_event_context_vppid = "VPPID";
142 const char * const config_event_context_pthread_id = "PTHREAD_ID";
143 const char * const config_event_context_hostname = "HOSTNAME";
144 const char * const config_event_context_ip = "IP";
145
146 static int config_entry_handler_filter(struct handler_filter_args *args,
147 const char *section, const char *name, const char *value)
148 {
149 int ret = 0;
150 struct config_entry entry = { section, name, value };
151
152 assert(args);
153
154 if (!section || !name || !value) {
155 ret = -EIO;
156 goto end;
157 }
158
159 if (args->section) {
160 if (strcmp(args->section, section)) {
161 goto end;
162 }
163 }
164
165 ret = args->handler(&entry, args->user_data);
166 end:
167 return ret;
168 }
169
170 LTTNG_HIDDEN
171 int config_get_section_entries(const char *override_path, const char *section,
172 config_entry_handler_cb handler, void *user_data)
173 {
174 int ret = 0;
175 FILE *config_file = NULL;
176 struct handler_filter_args filter = { section, handler, user_data };
177
178 if (override_path) {
179 config_file = fopen(override_path, "r");
180 if (config_file) {
181 DBG("Loaded daemon configuration file at %s",
182 override_path);
183 } else {
184 ERR("Failed to open daemon configuration file at %s",
185 override_path);
186 ret = -ENOENT;
187 goto end;
188 }
189 } else {
190 char *path = utils_get_home_dir();
191
192 /* Try to open the user's daemon configuration file */
193 if (path) {
194 ret = asprintf(&path, DEFAULT_DAEMON_HOME_CONFIGPATH, path);
195 if (ret < 0) {
196 goto end;
197 }
198
199 ret = 0;
200 config_file = fopen(path, "r");
201 if (config_file) {
202 DBG("Loaded daemon configuration file at %s", path);
203 }
204
205 free(path);
206 }
207
208 /* Try to open the system daemon configuration file */
209 if (!config_file) {
210 config_file = fopen(DEFAULT_DAEMON_HOME_CONFIGPATH, "r");
211 }
212 }
213
214 if (!config_file) {
215 DBG("No daemon configuration file found.");
216 goto end;
217 }
218
219 ret = ini_parse_file(config_file,
220 (ini_entry_handler) config_entry_handler_filter, (void *) &filter);
221
222 end:
223 return ret;
224 }
225
226 LTTNG_HIDDEN
227 int config_parse_value(const char *value)
228 {
229 int i, ret = 0;
230 char *endptr, *lower_str;
231 size_t len;
232 unsigned long v;
233
234 len = strlen(value);
235 if (!len) {
236 ret = -1;
237 goto end;
238 }
239
240 v = strtoul(value, &endptr, 10);
241 if (endptr != value) {
242 ret = v;
243 goto end;
244 }
245
246 lower_str = zmalloc(len + 1);
247 if (!lower_str) {
248 PERROR("zmalloc");
249 ret = -errno;
250 goto end;
251 }
252
253 for (i = 0; i < len; i++) {
254 lower_str[i] = tolower(value[i]);
255 }
256
257 if (!strcmp(lower_str, config_str_yes) ||
258 !strcmp(lower_str, config_str_true) ||
259 !strcmp(lower_str, config_str_on)) {
260 ret = 1;
261 } else if (!strcmp(lower_str, config_str_no) ||
262 !strcmp(lower_str, config_str_false) ||
263 !strcmp(lower_str, config_str_off)) {
264 ret = 0;
265 } else {
266 ret = -1;
267 }
268
269 free(lower_str);
270 end:
271 return ret;
272 }
273
274 /*
275 * Returns a xmlChar string which must be released using xmlFree().
276 */
277 static xmlChar *encode_string(const char *in_str)
278 {
279 xmlChar *out_str = NULL;
280 xmlCharEncodingHandlerPtr handler;
281 int out_len, ret, in_len;
282
283 assert(in_str);
284
285 handler = xmlFindCharEncodingHandler(config_xml_encoding);
286 if (!handler) {
287 ERR("xmlFindCharEncodingHandler return NULL!. Configure issue!");
288 goto end;
289 }
290
291 in_len = strlen(in_str);
292 /*
293 * Add 1 byte for the NULL terminted character. The factor 2 here is
294 * because UTF-8 can be on two bytes so this fits the worst case for each
295 * bytes.
296 */
297 out_len = (in_len * 2) + 1;
298 out_str = xmlMalloc(out_len);
299 if (!out_str) {
300 goto end;
301 }
302
303 ret = handler->input(out_str, &out_len, (const xmlChar *) in_str, &in_len);
304 if (ret < 0) {
305 xmlFree(out_str);
306 out_str = NULL;
307 goto end;
308 }
309
310 /* out_len is now the size of out_str */
311 out_str[out_len] = '\0';
312 end:
313 return out_str;
314 }
315
316 LTTNG_HIDDEN
317 struct config_writer *config_writer_create(int fd_output)
318 {
319 int ret;
320 struct config_writer *writer;
321 xmlOutputBufferPtr buffer;
322
323 writer = zmalloc(sizeof(struct config_writer));
324 if (!writer) {
325 PERROR("zmalloc config_writer_create");
326 goto end;
327 }
328
329 buffer = xmlOutputBufferCreateFd(fd_output, NULL);
330 if (!buffer) {
331 goto error_destroy;
332 }
333
334 writer->writer = xmlNewTextWriter(buffer);
335 ret = xmlTextWriterStartDocument(writer->writer, NULL,
336 config_xml_encoding, NULL);
337 if (ret < 0) {
338 goto error_destroy;
339 }
340
341 ret = xmlTextWriterSetIndentString(writer->writer,
342 BAD_CAST config_xml_indent_string);
343 if (ret) {
344 goto error_destroy;
345 }
346
347 ret = xmlTextWriterSetIndent(writer->writer, 1);
348 if (ret) {
349 goto error_destroy;
350 }
351
352 end:
353 return writer;
354 error_destroy:
355 config_writer_destroy(writer);
356 return NULL;
357 }
358
359 LTTNG_HIDDEN
360 int config_writer_destroy(struct config_writer *writer)
361 {
362 int ret = 0;
363
364 if (!writer) {
365 ret = -EINVAL;
366 goto end;
367 }
368
369 if (xmlTextWriterEndDocument(writer->writer) < 0) {
370 WARN("Could not close XML document");
371 ret = -EIO;
372 }
373
374 if (writer->writer) {
375 xmlFreeTextWriter(writer->writer);
376 }
377
378 free(writer);
379 end:
380 return ret;
381 }
382
383 LTTNG_HIDDEN
384 int config_writer_open_element(struct config_writer *writer,
385 const char *element_name)
386 {
387 int ret;
388 xmlChar *encoded_element_name;
389
390 if (!writer || !writer->writer || !element_name || !element_name[0]) {
391 ret = -1;
392 goto end;
393 }
394
395 encoded_element_name = encode_string(element_name);
396 if (!encoded_element_name) {
397 ret = -1;
398 goto end;
399 }
400
401 ret = xmlTextWriterStartElement(writer->writer, encoded_element_name);
402 xmlFree(encoded_element_name);
403 end:
404 return ret > 0 ? 0 : ret;
405 }
406
407 LTTNG_HIDDEN
408 int config_writer_close_element(struct config_writer *writer)
409 {
410 int ret;
411
412 if (!writer || !writer->writer) {
413 ret = -1;
414 goto end;
415 }
416
417 ret = xmlTextWriterEndElement(writer->writer);
418 end:
419 return ret > 0 ? 0 : ret;
420 }
421
422 LTTNG_HIDDEN
423 int config_writer_write_element_unsigned_int(struct config_writer *writer,
424 const char *element_name, uint64_t value)
425 {
426 int ret;
427 xmlChar *encoded_element_name;
428
429 if (!writer || !writer->writer || !element_name || !element_name[0]) {
430 ret = -1;
431 goto end;
432 }
433
434 encoded_element_name = encode_string(element_name);
435 if (!encoded_element_name) {
436 ret = -1;
437 goto end;
438 }
439
440 ret = xmlTextWriterWriteFormatElement(writer->writer,
441 encoded_element_name, "%" PRIu64, value);
442 xmlFree(encoded_element_name);
443 end:
444 return ret > 0 ? 0 : ret;
445 }
446
447 LTTNG_HIDDEN
448 int config_writer_write_element_signed_int(struct config_writer *writer,
449 const char *element_name, int64_t value)
450 {
451 int ret;
452 xmlChar *encoded_element_name;
453
454 if (!writer || !writer->writer || !element_name || !element_name[0]) {
455 ret = -1;
456 goto end;
457 }
458
459 encoded_element_name = encode_string(element_name);
460 if (!encoded_element_name) {
461 ret = -1;
462 goto end;
463 }
464
465 ret = xmlTextWriterWriteFormatElement(writer->writer,
466 encoded_element_name, "%" PRIi64, value);
467 xmlFree(encoded_element_name);
468 end:
469 return ret > 0 ? 0 : ret;
470 }
471
472 LTTNG_HIDDEN
473 int config_writer_write_element_bool(struct config_writer *writer,
474 const char *element_name, int value)
475 {
476 return config_writer_write_element_string(writer, element_name,
477 value ? config_xml_true : config_xml_false);
478 }
479
480 LTTNG_HIDDEN
481 int config_writer_write_element_string(struct config_writer *writer,
482 const char *element_name, const char *value)
483 {
484 int ret;
485 xmlChar *encoded_element_name = NULL;
486 xmlChar *encoded_value = NULL;
487
488 if (!writer || !writer->writer || !element_name || !element_name[0] ||
489 !value) {
490 ret = -1;
491 goto end;
492 }
493
494 encoded_element_name = encode_string(element_name);
495 if (!encoded_element_name) {
496 ret = -1;
497 goto end;
498 }
499
500 encoded_value = encode_string(value);
501 if (!encoded_value) {
502 ret = -1;
503 goto end;
504 }
505
506 ret = xmlTextWriterWriteElement(writer->writer, encoded_element_name,
507 encoded_value);
508 end:
509 xmlFree(encoded_element_name);
510 xmlFree(encoded_value);
511 return ret > 0 ? 0 : ret;
512 }
This page took 0.039544 seconds and 4 git commands to generate.