Optional test for the metadata regeneration
[lttng-tools.git] / src / common / config / session-config.c
CommitLineData
1501a7f3
JG
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
6c1c0768 18#define _LGPL_SOURCE
1501a7f3 19#include <assert.h>
1501a7f3 20#include <ctype.h>
1501a7f3
JG
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
36f2332b 24#include <inttypes.h>
dcf266c0
JG
25#include <dirent.h>
26#include <unistd.h>
27#include <sys/types.h>
28#include <sys/stat.h>
1501a7f3
JG
29
30#include <common/defaults.h>
31#include <common/error.h>
32#include <common/macros.h>
33#include <common/utils.h>
e8fa9fb0 34#include <common/compat/getenv.h>
fb198a11
JG
35#include <lttng/lttng-error.h>
36#include <libxml/parser.h>
37#include <libxml/valid.h>
38#include <libxml/xmlschemas.h>
dcf266c0
JG
39#include <libxml/tree.h>
40#include <lttng/lttng.h>
41#include <lttng/snapshot.h>
1501a7f3 42
f40ef1d5 43#include "session-config.h"
36f2332b 44#include "config-internal.h"
1501a7f3
JG
45
46struct handler_filter_args {
47 const char* section;
48 config_entry_handler_cb handler;
49 void *user_data;
50};
51
dcf266c0
JG
52struct session_config_validation_ctx {
53 xmlSchemaParserCtxtPtr parser_ctx;
54 xmlSchemaPtr schema;
55 xmlSchemaValidCtxtPtr schema_validation_ctx;
56};
57
1501a7f3
JG
58const char * const config_str_yes = "yes";
59const char * const config_str_true = "true";
60const char * const config_str_on = "on";
61const char * const config_str_no = "no";
62const char * const config_str_false = "false";
63const char * const config_str_off = "off";
36f2332b 64const char * const config_xml_encoding = "UTF-8";
fb198a11 65const size_t config_xml_encoding_bytes_per_char = 2; /* Size of the encoding's largest character */
36f2332b
JG
66const char * const config_xml_indent_string = "\t";
67const char * const config_xml_true = "true";
68const char * const config_xml_false = "false";
1501a7f3 69
fb198a11
JG
70const char * const config_element_channel = "channel";
71const char * const config_element_channels = "channels";
72const char * const config_element_domain = "domain";
73const char * const config_element_domains = "domains";
74const char * const config_element_event = "event";
75const char * const config_element_events = "events";
76const char * const config_element_context = "context";
77const char * const config_element_contexts = "contexts";
78const char * const config_element_attributes = "attributes";
79const char * const config_element_exclusion = "exclusion";
80const char * const config_element_exclusions = "exclusions";
81const char * const config_element_function_attributes = "function_attributes";
82const char * const config_element_probe_attributes = "probe_attributes";
83const char * const config_element_symbol_name = "symbol_name";
84const char * const config_element_address = "address";
85const char * const config_element_offset = "offset";
86const char * const config_element_name = "name";
87const char * const config_element_enabled = "enabled";
88const char * const config_element_overwrite_mode = "overwrite_mode";
89const char * const config_element_subbuf_size = "subbuffer_size";
90const char * const config_element_num_subbuf = "subbuffer_count";
91const char * const config_element_switch_timer_interval = "switch_timer_interval";
92const char * const config_element_read_timer_interval = "read_timer_interval";
93const char * const config_element_output = "output";
94const char * const config_element_output_type = "output_type";
95const char * const config_element_tracefile_size = "tracefile_size";
96const char * const config_element_tracefile_count = "tracefile_count";
97const char * const config_element_live_timer_interval = "live_timer_interval";
fb83fe64
JD
98const char * const config_element_discarded_events = "discarded_events";
99const char * const config_element_lost_packets = "lost_packets";
fb198a11
JG
100const char * const config_element_type = "type";
101const char * const config_element_buffer_type = "buffer_type";
102const char * const config_element_session = "session";
103const char * const config_element_sessions = "sessions";
045fc617
JG
104const char * const config_element_context_perf = "perf";
105const char * const config_element_context_app = "app";
106const char * const config_element_context_app_provider_name = "provider_name";
107const char * const config_element_context_app_ctx_name = "ctx_name";
fb198a11
JG
108const char * const config_element_config = "config";
109const char * const config_element_started = "started";
110const char * const config_element_snapshot_mode = "snapshot_mode";
111const char * const config_element_loglevel = "loglevel";
112const char * const config_element_loglevel_type = "loglevel_type";
113const char * const config_element_filter = "filter";
7b4aa11d 114const char * const config_element_filter_expression = "filter_expression";
fb198a11
JG
115const char * const config_element_snapshot_outputs = "snapshot_outputs";
116const char * const config_element_consumer_output = "consumer_output";
117const char * const config_element_destination = "destination";
118const char * const config_element_path = "path";
119const char * const config_element_net_output = "net_output";
120const char * const config_element_control_uri = "control_uri";
121const char * const config_element_data_uri = "data_uri";
122const char * const config_element_max_size = "max_size";
ccf10263
MD
123const char * const config_element_pid = "pid";
124const char * const config_element_pids = "pids";
9e7c9f56 125const char * const config_element_shared_memory_path = "shared_memory_path";
ebbf5ab7
JR
126const char * const config_element_pid_tracker = "pid_tracker";
127const char * const config_element_trackers = "trackers";
847a5916
JR
128const char * const config_element_targets = "targets";
129const char * const config_element_target_pid = "pid_target";
fb198a11
JG
130
131const char * const config_domain_type_kernel = "KERNEL";
132const char * const config_domain_type_ust = "UST";
133const char * const config_domain_type_jul = "JUL";
5cdb6027 134const char * const config_domain_type_log4j = "LOG4J";
0e115563 135const char * const config_domain_type_python = "PYTHON";
fb198a11
JG
136
137const char * const config_buffer_type_per_pid = "PER_PID";
138const char * const config_buffer_type_per_uid = "PER_UID";
139const char * const config_buffer_type_global = "GLOBAL";
140
141const char * const config_overwrite_mode_discard = "DISCARD";
142const char * const config_overwrite_mode_overwrite = "OVERWRITE";
143
144const char * const config_output_type_splice = "SPLICE";
145const char * const config_output_type_mmap = "MMAP";
146
147const char * const config_loglevel_type_all = "ALL";
148const char * const config_loglevel_type_range = "RANGE";
149const char * const config_loglevel_type_single = "SINGLE";
150
151const char * const config_event_type_all = "ALL";
152const char * const config_event_type_tracepoint = "TRACEPOINT";
153const char * const config_event_type_probe = "PROBE";
154const char * const config_event_type_function = "FUNCTION";
155const char * const config_event_type_function_entry = "FUNCTION_ENTRY";
156const char * const config_event_type_noop = "NOOP";
157const char * const config_event_type_syscall = "SYSCALL";
158const char * const config_event_type_kprobe = "KPROBE";
159const char * const config_event_type_kretprobe = "KRETPROBE";
160
161const char * const config_event_context_pid = "PID";
162const char * const config_event_context_procname = "PROCNAME";
163const char * const config_event_context_prio = "PRIO";
164const char * const config_event_context_nice = "NICE";
165const char * const config_event_context_vpid = "VPID";
166const char * const config_event_context_tid = "TID";
167const char * const config_event_context_vtid = "VTID";
168const char * const config_event_context_ppid = "PPID";
169const char * const config_event_context_vppid = "VPPID";
170const char * const config_event_context_pthread_id = "PTHREAD_ID";
171const char * const config_event_context_hostname = "HOSTNAME";
172const char * const config_event_context_ip = "IP";
e885a367 173const char * const config_event_context_perf_thread_counter = "PERF_THREAD_COUNTER";
045fc617
JG
174const char * const config_event_context_app = "APP";
175
fb198a11 176
dcf266c0
JG
177struct consumer_output {
178 int enabled;
179 char *path;
180 char *control_uri;
181 char *data_uri;
182};
183
1501a7f3
JG
184static int config_entry_handler_filter(struct handler_filter_args *args,
185 const char *section, const char *name, const char *value)
186{
187 int ret = 0;
188 struct config_entry entry = { section, name, value };
189
190 assert(args);
191
192 if (!section || !name || !value) {
193 ret = -EIO;
194 goto end;
195 }
196
197 if (args->section) {
198 if (strcmp(args->section, section)) {
199 goto end;
200 }
201 }
202
203 ret = args->handler(&entry, args->user_data);
204end:
205 return ret;
206}
207
208LTTNG_HIDDEN
209int config_get_section_entries(const char *override_path, const char *section,
210 config_entry_handler_cb handler, void *user_data)
211{
212 int ret = 0;
7ab02a27 213 char *path;
1501a7f3
JG
214 FILE *config_file = NULL;
215 struct handler_filter_args filter = { section, handler, user_data };
216
7ab02a27
DG
217 /* First, try system-wide conf. file. */
218 path = DEFAULT_DAEMON_SYSTEM_CONFIGPATH;
219
220 config_file = fopen(path, "r");
221 if (config_file) {
222 DBG("Loading daemon conf file at %s", path);
223 /*
224 * Return value is not very important here since error or not, we
225 * continue and try the next possible conf. file.
226 */
227 (void) ini_parse_file(config_file,
228 (ini_entry_handler) config_entry_handler_filter,
229 (void *) &filter);
230 fclose(config_file);
231 }
232
233 /* Second is the user local configuration. */
234 path = utils_get_home_dir();
235 if (path) {
236 char fullpath[PATH_MAX];
237
238 ret = snprintf(fullpath, sizeof(fullpath),
239 DEFAULT_DAEMON_HOME_CONFIGPATH, path);
240 if (ret < 0) {
241 PERROR("snprintf user conf. path");
242 goto error;
243 }
244
245 config_file = fopen(fullpath, "r");
246 if (config_file) {
247 DBG("Loading daemon user conf file at %s", path);
248 /*
249 * Return value is not very important here since error or not, we
250 * continue and try the next possible conf. file.
251 */
252 (void) ini_parse_file(config_file,
253 (ini_entry_handler) config_entry_handler_filter,
254 (void *) &filter);
255 fclose(config_file);
256 }
257 }
258
259 /* Final path is the one that the user might have provided. */
1501a7f3
JG
260 if (override_path) {
261 config_file = fopen(override_path, "r");
262 if (config_file) {
7ab02a27
DG
263 DBG("Loading daemon command line conf file at %s", override_path);
264 (void) ini_parse_file(config_file,
265 (ini_entry_handler) config_entry_handler_filter,
266 (void *) &filter);
267 fclose(config_file);
1501a7f3
JG
268 } else {
269 ERR("Failed to open daemon configuration file at %s",
270 override_path);
271 ret = -ENOENT;
7ab02a27 272 goto error;
1501a7f3
JG
273 }
274 }
275
7ab02a27
DG
276 /* Everything went well. */
277 ret = 0;
1501a7f3 278
7ab02a27 279error:
1501a7f3
JG
280 return ret;
281}
282
283LTTNG_HIDDEN
284int config_parse_value(const char *value)
285{
286 int i, ret = 0;
287 char *endptr, *lower_str;
288 size_t len;
289 unsigned long v;
290
291 len = strlen(value);
292 if (!len) {
293 ret = -1;
294 goto end;
295 }
296
297 v = strtoul(value, &endptr, 10);
298 if (endptr != value) {
299 ret = v;
300 goto end;
301 }
302
303 lower_str = zmalloc(len + 1);
304 if (!lower_str) {
305 PERROR("zmalloc");
306 ret = -errno;
307 goto end;
308 }
309
310 for (i = 0; i < len; i++) {
311 lower_str[i] = tolower(value[i]);
312 }
313
314 if (!strcmp(lower_str, config_str_yes) ||
315 !strcmp(lower_str, config_str_true) ||
316 !strcmp(lower_str, config_str_on)) {
317 ret = 1;
318 } else if (!strcmp(lower_str, config_str_no) ||
319 !strcmp(lower_str, config_str_false) ||
320 !strcmp(lower_str, config_str_off)) {
321 ret = 0;
322 } else {
323 ret = -1;
324 }
325
326 free(lower_str);
327end:
328 return ret;
329}
36f2332b
JG
330
331/*
332 * Returns a xmlChar string which must be released using xmlFree().
333 */
334static xmlChar *encode_string(const char *in_str)
335{
336 xmlChar *out_str = NULL;
337 xmlCharEncodingHandlerPtr handler;
338 int out_len, ret, in_len;
339
340 assert(in_str);
341
342 handler = xmlFindCharEncodingHandler(config_xml_encoding);
343 if (!handler) {
344 ERR("xmlFindCharEncodingHandler return NULL!. Configure issue!");
345 goto end;
346 }
347
348 in_len = strlen(in_str);
349 /*
f76d886f
JG
350 * Add 1 byte for the NULL terminted character. The factor 4 here is
351 * used because UTF-8 characters can take up to 4 bytes.
36f2332b 352 */
f76d886f 353 out_len = (in_len * 4) + 1;
36f2332b
JG
354 out_str = xmlMalloc(out_len);
355 if (!out_str) {
356 goto end;
357 }
358
359 ret = handler->input(out_str, &out_len, (const xmlChar *) in_str, &in_len);
360 if (ret < 0) {
361 xmlFree(out_str);
362 out_str = NULL;
363 goto end;
364 }
365
366 /* out_len is now the size of out_str */
367 out_str[out_len] = '\0';
368end:
369 return out_str;
370}
371
372LTTNG_HIDDEN
705bb62f 373struct config_writer *config_writer_create(int fd_output, int indent)
36f2332b
JG
374{
375 int ret;
376 struct config_writer *writer;
377 xmlOutputBufferPtr buffer;
378
379 writer = zmalloc(sizeof(struct config_writer));
380 if (!writer) {
381 PERROR("zmalloc config_writer_create");
382 goto end;
383 }
384
385 buffer = xmlOutputBufferCreateFd(fd_output, NULL);
386 if (!buffer) {
387 goto error_destroy;
388 }
389
390 writer->writer = xmlNewTextWriter(buffer);
391 ret = xmlTextWriterStartDocument(writer->writer, NULL,
392 config_xml_encoding, NULL);
393 if (ret < 0) {
394 goto error_destroy;
395 }
396
397 ret = xmlTextWriterSetIndentString(writer->writer,
398 BAD_CAST config_xml_indent_string);
705bb62f 399 if (ret) {
36f2332b
JG
400 goto error_destroy;
401 }
402
705bb62f
JRJ
403 ret = xmlTextWriterSetIndent(writer->writer, indent);
404 if (ret) {
36f2332b
JG
405 goto error_destroy;
406 }
407
408end:
409 return writer;
410error_destroy:
411 config_writer_destroy(writer);
412 return NULL;
413}
414
415LTTNG_HIDDEN
416int config_writer_destroy(struct config_writer *writer)
417{
418 int ret = 0;
419
420 if (!writer) {
421 ret = -EINVAL;
422 goto end;
423 }
424
425 if (xmlTextWriterEndDocument(writer->writer) < 0) {
426 WARN("Could not close XML document");
427 ret = -EIO;
428 }
429
430 if (writer->writer) {
431 xmlFreeTextWriter(writer->writer);
432 }
433
434 free(writer);
435end:
436 return ret;
437}
438
439LTTNG_HIDDEN
440int config_writer_open_element(struct config_writer *writer,
441 const char *element_name)
442{
443 int ret;
444 xmlChar *encoded_element_name;
445
446 if (!writer || !writer->writer || !element_name || !element_name[0]) {
447 ret = -1;
448 goto end;
449 }
450
451 encoded_element_name = encode_string(element_name);
452 if (!encoded_element_name) {
453 ret = -1;
454 goto end;
455 }
456
457 ret = xmlTextWriterStartElement(writer->writer, encoded_element_name);
458 xmlFree(encoded_element_name);
459end:
28676a1d 460 return ret >= 0 ? 0 : ret;
36f2332b
JG
461}
462
e10b6a1c
JG
463LTTNG_HIDDEN
464int config_writer_write_attribute(struct config_writer *writer,
465 const char *name, const char *value)
466{
467 int ret;
468 xmlChar *encoded_name = NULL;
469 xmlChar *encoded_value = NULL;
470
471 if (!writer || !writer->writer || !name || !name[0]) {
472 ret = -1;
473 goto end;
474 }
475
476 encoded_name = encode_string(name);
477 if (!encoded_name) {
478 ret = -1;
479 goto end;
480 }
481
482 encoded_value = encode_string(value);
483 if (!encoded_value) {
484 ret = -1;
485 goto end;
486 }
487
488 ret = xmlTextWriterWriteAttribute(writer->writer, encoded_name,
489 encoded_value);
490end:
491 xmlFree(encoded_name);
492 xmlFree(encoded_value);
493 return ret >= 0 ? 0 : ret;
494}
495
36f2332b
JG
496LTTNG_HIDDEN
497int config_writer_close_element(struct config_writer *writer)
498{
499 int ret;
500
501 if (!writer || !writer->writer) {
502 ret = -1;
503 goto end;
504 }
505
506 ret = xmlTextWriterEndElement(writer->writer);
507end:
28676a1d 508 return ret >= 0 ? 0 : ret;
36f2332b
JG
509}
510
511LTTNG_HIDDEN
512int config_writer_write_element_unsigned_int(struct config_writer *writer,
513 const char *element_name, uint64_t value)
514{
515 int ret;
516 xmlChar *encoded_element_name;
517
518 if (!writer || !writer->writer || !element_name || !element_name[0]) {
519 ret = -1;
520 goto end;
521 }
522
523 encoded_element_name = encode_string(element_name);
524 if (!encoded_element_name) {
525 ret = -1;
526 goto end;
527 }
528
529 ret = xmlTextWriterWriteFormatElement(writer->writer,
530 encoded_element_name, "%" PRIu64, value);
531 xmlFree(encoded_element_name);
532end:
28676a1d 533 return ret >= 0 ? 0 : ret;
36f2332b
JG
534}
535
536LTTNG_HIDDEN
537int config_writer_write_element_signed_int(struct config_writer *writer,
538 const char *element_name, int64_t value)
539{
540 int ret;
541 xmlChar *encoded_element_name;
542
543 if (!writer || !writer->writer || !element_name || !element_name[0]) {
544 ret = -1;
545 goto end;
546 }
547
548 encoded_element_name = encode_string(element_name);
549 if (!encoded_element_name) {
550 ret = -1;
551 goto end;
552 }
553
554 ret = xmlTextWriterWriteFormatElement(writer->writer,
555 encoded_element_name, "%" PRIi64, value);
556 xmlFree(encoded_element_name);
557end:
28676a1d 558 return ret >= 0 ? 0 : ret;
36f2332b
JG
559}
560
561LTTNG_HIDDEN
562int config_writer_write_element_bool(struct config_writer *writer,
563 const char *element_name, int value)
564{
565 return config_writer_write_element_string(writer, element_name,
566 value ? config_xml_true : config_xml_false);
567}
568
569LTTNG_HIDDEN
570int config_writer_write_element_string(struct config_writer *writer,
571 const char *element_name, const char *value)
572{
573 int ret;
574 xmlChar *encoded_element_name = NULL;
575 xmlChar *encoded_value = NULL;
576
577 if (!writer || !writer->writer || !element_name || !element_name[0] ||
578 !value) {
579 ret = -1;
580 goto end;
581 }
582
583 encoded_element_name = encode_string(element_name);
584 if (!encoded_element_name) {
585 ret = -1;
586 goto end;
587 }
588
589 encoded_value = encode_string(value);
590 if (!encoded_value) {
591 ret = -1;
592 goto end;
593 }
594
595 ret = xmlTextWriterWriteElement(writer->writer, encoded_element_name,
dcf266c0 596 encoded_value);
36f2332b
JG
597end:
598 xmlFree(encoded_element_name);
599 xmlFree(encoded_value);
28676a1d 600 return ret >= 0 ? 0 : ret;
36f2332b 601}
dcf266c0
JG
602
603static
604void xml_error_handler(void *ctx, const char *format, ...)
605{
606 char *errMsg;
607 va_list args;
608 int ret;
609
610 va_start(args, format);
611 ret = vasprintf(&errMsg, format, args);
6c043b48 612 va_end(args);
dcf266c0
JG
613 if (ret == -1) {
614 ERR("String allocation failed in xml error handler");
615 return;
616 }
dcf266c0
JG
617
618 fprintf(stderr, "XML Error: %s", errMsg);
619 free(errMsg);
620}
621
622static
623void fini_session_config_validation_ctx(
624 struct session_config_validation_ctx *ctx)
625{
626 if (ctx->parser_ctx) {
627 xmlSchemaFreeParserCtxt(ctx->parser_ctx);
628 }
629
630 if (ctx->schema) {
631 xmlSchemaFree(ctx->schema);
632 }
633
634 if (ctx->schema_validation_ctx) {
635 xmlSchemaFreeValidCtxt(ctx->schema_validation_ctx);
636 }
637
638 memset(ctx, 0, sizeof(struct session_config_validation_ctx));
639}
640
54e399cb
JG
641static
642char *get_session_config_xsd_path()
643{
644 char *xsd_path;
e8fa9fb0 645 const char *base_path = lttng_secure_getenv(DEFAULT_SESSION_CONFIG_XSD_PATH_ENV);
54e399cb
JG
646 size_t base_path_len;
647 size_t max_path_len;
648
649 if (!base_path) {
650 base_path = DEFAULT_SESSION_CONFIG_XSD_PATH;
651 }
652
653 base_path_len = strlen(base_path);
654 max_path_len = base_path_len +
655 sizeof(DEFAULT_SESSION_CONFIG_XSD_FILENAME) + 1;
656 xsd_path = zmalloc(max_path_len);
657 if (!xsd_path) {
658 goto end;
659 }
660
661 strncpy(xsd_path, base_path, max_path_len);
662 if (xsd_path[base_path_len - 1] != '/') {
663 xsd_path[base_path_len++] = '/';
664 }
665
666 strncpy(xsd_path + base_path_len, DEFAULT_SESSION_CONFIG_XSD_FILENAME,
667 max_path_len - base_path_len);
668end:
669 return xsd_path;
670}
671
dcf266c0
JG
672static
673int init_session_config_validation_ctx(
674 struct session_config_validation_ctx *ctx)
675{
676 int ret;
54e399cb
JG
677 char *xsd_path = get_session_config_xsd_path();
678
679 if (!xsd_path) {
680 ret = -LTTNG_ERR_NOMEM;
681 goto end;
682 }
dcf266c0 683
54e399cb 684 ctx->parser_ctx = xmlSchemaNewParserCtxt(xsd_path);
dcf266c0
JG
685 if (!ctx->parser_ctx) {
686 ERR("XSD parser context creation failed");
687 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
688 goto end;
689 }
690 xmlSchemaSetParserErrors(ctx->parser_ctx, xml_error_handler,
691 xml_error_handler, NULL);
692
693 ctx->schema = xmlSchemaParse(ctx->parser_ctx);
694 if (!ctx->schema) {
695 ERR("XSD parsing failed");
696 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
697 goto end;
698 }
699
700 ctx->schema_validation_ctx = xmlSchemaNewValidCtxt(ctx->schema);
701 if (!ctx->schema_validation_ctx) {
702 ERR("XSD validation context creation failed");
703 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
704 goto end;
705 }
706
707 xmlSchemaSetValidErrors(ctx->schema_validation_ctx, xml_error_handler,
708 xml_error_handler, NULL);
709 ret = 0;
710
711end:
712 if (ret) {
713 fini_session_config_validation_ctx(ctx);
714 }
715
54e399cb 716 free(xsd_path);
dcf266c0
JG
717 return ret;
718}
719
720static
721int parse_uint(xmlChar *str, uint64_t *val)
722{
723 int ret;
724 char *endptr;
725
726 if (!str || !val) {
727 ret = -1;
728 goto end;
729 }
730
731 *val = strtoull((const char *) str, &endptr, 10);
732 if (!endptr || *endptr) {
733 ret = -1;
734 } else {
735 ret = 0;
736 }
737
738end:
739 return ret;
740}
741
742static
743int parse_int(xmlChar *str, int64_t *val)
744{
745 int ret;
746 char *endptr;
747
748 if (!str || !val) {
749 ret = -1;
750 goto end;
751 }
752
753 *val = strtoll((const char *) str, &endptr, 10);
754 if (!endptr || *endptr) {
755 ret = -1;
756 } else {
757 ret = 0;
758 }
759
760end:
761 return ret;
762}
763
764static
765int parse_bool(xmlChar *str, int *val)
766{
767 int ret = 0;
768
769 if (!str || !val) {
770 ret = -1;
771 goto end;
772 }
773
774 if (!strcmp((const char *) str, config_xml_true)) {
775 *val = 1;
776 } else if (!strcmp((const char *) str, config_xml_false)) {
777 *val = 0;
778 } else {
779 WARN("Invalid boolean value encoutered (%s).",
780 (const char *) str);
781 ret = -1;
782 }
783end:
784 return ret;
785}
786
787static
788int get_domain_type(xmlChar *domain)
789{
790 int ret;
791
792 if (!domain) {
793 goto error;
794 }
795
796 if (!strcmp((char *) domain, config_domain_type_kernel)) {
797 ret = LTTNG_DOMAIN_KERNEL;
798 } else if (!strcmp((char *) domain, config_domain_type_ust)) {
799 ret = LTTNG_DOMAIN_UST;
800 } else if (!strcmp((char *) domain, config_domain_type_jul)) {
801 ret = LTTNG_DOMAIN_JUL;
5cdb6027
DG
802 } else if (!strcmp((char *) domain, config_domain_type_log4j)) {
803 ret = LTTNG_DOMAIN_LOG4J;
0e115563
DG
804 } else if (!strcmp((char *) domain, config_domain_type_python)) {
805 ret = LTTNG_DOMAIN_PYTHON;
dcf266c0
JG
806 } else {
807 goto error;
808 }
809
810 return ret;
811error:
812 return -1;
813}
814
815static
816int get_buffer_type(xmlChar *buffer_type)
817{
818 int ret;
819
820 if (!buffer_type) {
821 goto error;
822 }
823
824 if (!strcmp((char *) buffer_type, config_buffer_type_global)) {
825 ret = LTTNG_BUFFER_GLOBAL;
826 } else if (!strcmp((char *) buffer_type, config_buffer_type_per_uid)) {
827 ret = LTTNG_BUFFER_PER_UID;
828 } else if (!strcmp((char *) buffer_type, config_buffer_type_per_pid)) {
829 ret = LTTNG_BUFFER_PER_PID;
830 } else {
831 goto error;
832 }
833
834 return ret;
835error:
836 return -1;
837}
838
839static
840int get_overwrite_mode(xmlChar *overwrite_mode)
841{
842 int ret;
843
844 if (!overwrite_mode) {
845 goto error;
846 }
847
848 if (!strcmp((char *) overwrite_mode, config_overwrite_mode_overwrite)) {
849 ret = 1;
850 } else if (!strcmp((char *) overwrite_mode,
851 config_overwrite_mode_discard)) {
852 ret = 0;
853 } else {
854 goto error;
855 }
856
857 return ret;
858error:
859 return -1;
860}
861
862static
863int get_output_type(xmlChar *output_type)
864{
865 int ret;
866
867 if (!output_type) {
868 goto error;
869 }
870
871 if (!strcmp((char *) output_type, config_output_type_mmap)) {
872 ret = LTTNG_EVENT_MMAP;
873 } else if (!strcmp((char *) output_type, config_output_type_splice)) {
874 ret = LTTNG_EVENT_SPLICE;
875 } else {
876 goto error;
877 }
878
879 return ret;
880error:
881 return -1;
882}
883
884static
885int get_event_type(xmlChar *event_type)
886{
887 int ret;
888
889 if (!event_type) {
890 goto error;
891 }
892
893 if (!strcmp((char *) event_type, config_event_type_all)) {
894 ret = LTTNG_EVENT_ALL;
895 } else if (!strcmp((char *) event_type, config_event_type_tracepoint)) {
896 ret = LTTNG_EVENT_TRACEPOINT;
897 } else if (!strcmp((char *) event_type, config_event_type_probe)) {
898 ret = LTTNG_EVENT_PROBE;
899 } else if (!strcmp((char *) event_type, config_event_type_function)) {
900 ret = LTTNG_EVENT_FUNCTION;
901 } else if (!strcmp((char *) event_type,
902 config_event_type_function_entry)) {
903 ret = LTTNG_EVENT_FUNCTION_ENTRY;
904 } else if (!strcmp((char *) event_type, config_event_type_noop)) {
905 ret = LTTNG_EVENT_NOOP;
906 } else if (!strcmp((char *) event_type, config_event_type_syscall)) {
907 ret = LTTNG_EVENT_SYSCALL;
908 } else {
909 goto error;
910 }
911
912 return ret;
913error:
914 return -1;
915}
916
917static
918int get_loglevel_type(xmlChar *loglevel_type)
919{
920 int ret;
921
922 if (!loglevel_type) {
923 goto error;
924 }
925
926 if (!strcmp((char *) loglevel_type, config_loglevel_type_all)) {
927 ret = LTTNG_EVENT_LOGLEVEL_ALL;
928 } else if (!strcmp((char *) loglevel_type,
929 config_loglevel_type_range)) {
930 ret = LTTNG_EVENT_LOGLEVEL_RANGE;
931 } else if (!strcmp((char *) loglevel_type,
932 config_loglevel_type_single)) {
933 ret = LTTNG_EVENT_LOGLEVEL_SINGLE;
934 } else {
935 goto error;
936 }
937
938 return ret;
939error:
940 return -1;
941}
942
943/*
944 * Return the context type or -1 on error.
945 */
946static
947int get_context_type(xmlChar *context_type)
948{
949 int ret;
950
951 if (!context_type) {
952 goto error;
953 }
954
955 if (!strcmp((char *) context_type, config_event_context_pid)) {
956 ret = LTTNG_EVENT_CONTEXT_PID;
957 } else if (!strcmp((char *) context_type,
958 config_event_context_procname)) {
959 ret = LTTNG_EVENT_CONTEXT_PROCNAME;
960 } else if (!strcmp((char *) context_type,
961 config_event_context_prio)) {
962 ret = LTTNG_EVENT_CONTEXT_PRIO;
963 } else if (!strcmp((char *) context_type,
964 config_event_context_nice)) {
965 ret = LTTNG_EVENT_CONTEXT_NICE;
966 } else if (!strcmp((char *) context_type,
967 config_event_context_vpid)) {
968 ret = LTTNG_EVENT_CONTEXT_VPID;
969 } else if (!strcmp((char *) context_type,
970 config_event_context_tid)) {
971 ret = LTTNG_EVENT_CONTEXT_TID;
972 } else if (!strcmp((char *) context_type,
973 config_event_context_vtid)) {
974 ret = LTTNG_EVENT_CONTEXT_VTID;
975 } else if (!strcmp((char *) context_type,
976 config_event_context_ppid)) {
977 ret = LTTNG_EVENT_CONTEXT_PPID;
978 } else if (!strcmp((char *) context_type,
979 config_event_context_vppid)) {
980 ret = LTTNG_EVENT_CONTEXT_VPPID;
981 } else if (!strcmp((char *) context_type,
982 config_event_context_pthread_id)) {
983 ret = LTTNG_EVENT_CONTEXT_PTHREAD_ID;
984 } else if (!strcmp((char *) context_type,
985 config_event_context_hostname)) {
986 ret = LTTNG_EVENT_CONTEXT_HOSTNAME;
987 } else if (!strcmp((char *) context_type,
988 config_event_context_ip)) {
989 ret = LTTNG_EVENT_CONTEXT_IP;
990 } else {
991 goto error;
992 }
993
994 return ret;
995error:
996 return -1;
997}
998
999static
1000int init_domain(xmlNodePtr domain_node, struct lttng_domain *domain)
1001{
1002 int ret;
1003 xmlNodePtr node;
1004
1005 for (node = xmlFirstElementChild(domain_node); node;
1006 node = xmlNextElementSibling(node)) {
1007 if (!strcmp((const char *) node->name, config_element_type)) {
1008 /* domain type */
1009 xmlChar *node_content = xmlNodeGetContent(node);
1010 if (!node_content) {
1011 ret = -LTTNG_ERR_NOMEM;
1012 goto end;
1013 }
1014
1015 ret = get_domain_type(node_content);
1016 free(node_content);
1017 if (ret < 0) {
1018 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1019 goto end;
1020 }
1021
1022 domain->type = ret;
1023 } else if (!strcmp((const char *) node->name,
1024 config_element_buffer_type)) {
1025 /* buffer type */
1026 xmlChar *node_content = xmlNodeGetContent(node);
1027 if (!node_content) {
1028 ret = -LTTNG_ERR_NOMEM;
1029 goto end;
1030 }
1031
1032 ret = get_buffer_type(node_content);
1033 free(node_content);
1034 if (ret < 0) {
1035 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1036 goto end;
1037 }
1038
1039 domain->buf_type = ret;
1040 }
1041 }
1042 ret = 0;
1043end:
1044 return ret;
1045}
1046
1047static
1048int get_net_output_uris(xmlNodePtr net_output_node, char **control_uri,
1049 char **data_uri)
1050{
1051 xmlNodePtr node;
1052
1053 for (node = xmlFirstElementChild(net_output_node); node;
1054 node = xmlNextElementSibling(node)) {
1055 if (!strcmp((const char *) node->name, config_element_control_uri)) {
1056 /* control_uri */
1057 *control_uri = (char *) xmlNodeGetContent(node);
1058 if (!*control_uri) {
1059 break;
1060 }
1061 } else {
1062 /* data_uri */
1063 *data_uri = (char *) xmlNodeGetContent(node);
1064 if (!*data_uri) {
1065 break;
1066 }
1067 }
1068 }
1069
1070 return *control_uri || *data_uri ? 0 : -LTTNG_ERR_LOAD_INVALID_CONFIG;
1071}
1072
1073static
1074int process_consumer_output(xmlNodePtr consumer_output_node,
1075 struct consumer_output *output)
1076{
1077 int ret;
1078 xmlNodePtr node;
1079
1080 assert(output);
1081
1082 for (node = xmlFirstElementChild(consumer_output_node); node;
1083 node = xmlNextElementSibling(node)) {
1084 if (!strcmp((const char *) node->name, config_element_enabled)) {
1085 xmlChar *enabled_str = xmlNodeGetContent(node);
1086
1087 /* enabled */
1088 if (!enabled_str) {
1089 ret = -LTTNG_ERR_NOMEM;
1090 goto end;
1091 }
1092
1093 ret = parse_bool(enabled_str, &output->enabled);
1094 free(enabled_str);
1095 if (ret) {
1096 goto end;
1097 }
1098 } else {
1099 xmlNodePtr output_type_node;
1100
1101 /* destination */
1102 output_type_node = xmlFirstElementChild(node);
1103 if (!output_type_node) {
1104 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1105 goto end;
1106 }
1107
1108 if (!strcmp((const char *) output_type_node->name,
1109 config_element_path)) {
1110 /* path */
1111 output->path = (char *) xmlNodeGetContent(output_type_node);
1112 if (!output->path) {
1113 ret = -LTTNG_ERR_NOMEM;
1114 goto end;
1115 }
1116 } else {
1117 /* net_output */
1118 ret = get_net_output_uris(output_type_node,
1119 &output->control_uri, &output->data_uri);
1120 if (ret) {
1121 goto end;
1122 }
1123 }
1124 }
1125 }
1126 ret = 0;
1127
1128end:
1129 if (ret) {
1130 free(output->path);
1131 free(output->control_uri);
1132 free(output->data_uri);
1133 memset(output, 0, sizeof(struct consumer_output));
1134 }
1135 return ret;
1136}
1137
1138static
1139int create_session_net_output(const char *name, struct lttng_domain *domain,
1140 const char *control_uri, const char *data_uri)
1141{
1142 int ret;
1143 struct lttng_handle *handle;
1144 const char *uri = NULL;
1145
1146 assert(name);
1147 assert(domain);
1148
1149 handle = lttng_create_handle(name, domain);
1150 if (!handle) {
1151 ret = -LTTNG_ERR_NOMEM;
1152 goto end;
1153 }
1154
1155 if (!control_uri || !data_uri) {
1156 uri = control_uri ? control_uri : data_uri;
1157 control_uri = uri;
1158 data_uri = uri;
1159 }
1160
1161 ret = lttng_set_consumer_url(handle, control_uri, data_uri);
1162 lttng_destroy_handle(handle);
1163end:
1164 return ret;
1165}
1166
1167static
1168int create_snapshot_session(const char *session_name, xmlNodePtr output_node)
1169{
1170 int ret;
1171 xmlNodePtr node = NULL;
1172 xmlNodePtr snapshot_output_list_node;
1173 xmlNodePtr snapshot_output_node;
1174
1175 assert(session_name);
1176
1177 ret = lttng_create_session_snapshot(session_name, NULL);
1178 if (ret) {
1179 goto end;
1180 }
1181
1182 if (!output_node) {
1183 goto end;
1184 }
1185
1186 snapshot_output_list_node = xmlFirstElementChild(output_node);
1187
1188 /* Parse and create snapshot outputs */
1189
1190 for (snapshot_output_node =
1191 xmlFirstElementChild(snapshot_output_list_node);
1192 snapshot_output_node; snapshot_output_node =
1193 xmlNextElementSibling(snapshot_output_node)) {
1194 char *name = NULL;
1195 uint64_t max_size = UINT64_MAX;
1196 struct consumer_output output = { 0 };
1197 struct lttng_snapshot_output *snapshot_output = NULL;
1198
1199 for (node = xmlFirstElementChild(snapshot_output_node); node;
1200 node = xmlNextElementSibling(node)) {
1201 if (!strcmp((const char *) node->name,
1202 config_element_name)) {
1203 /* name */
1204 name = (char *) xmlNodeGetContent(node);
1205 if (!name) {
1206 ret = -LTTNG_ERR_NOMEM;
1207 goto error_snapshot_output;
1208 }
1209 } else if (!strcmp((const char *) node->name,
1210 config_element_max_size)) {
1211 xmlChar *content = xmlNodeGetContent(node);
1212
1213 /* max_size */
1214 if (!content) {
1215 ret = -LTTNG_ERR_NOMEM;
1216 goto error_snapshot_output;
1217 }
1218 ret = parse_uint(content, &max_size);
1219 free(content);
1220 if (ret) {
1221 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1222 goto error_snapshot_output;
1223 }
1224 } else {
1225 /* consumer_output */
1226 ret = process_consumer_output(node, &output);
1227 if (ret) {
1228 goto error_snapshot_output;
1229 }
1230 }
1231 }
1232
1233 snapshot_output = lttng_snapshot_output_create();
1234 if (!snapshot_output) {
1235 ret = -LTTNG_ERR_NOMEM;
1236 goto error_snapshot_output;
1237 }
1238
1239 ret = lttng_snapshot_output_set_name(name, snapshot_output);
1240 if (ret) {
1241 goto error_snapshot_output;
1242 }
1243
1244 ret = lttng_snapshot_output_set_size(max_size, snapshot_output);
1245 if (ret) {
1246 goto error_snapshot_output;
1247 }
1248
1249 if (output.path) {
1250 ret = lttng_snapshot_output_set_ctrl_url(output.path,
1251 snapshot_output);
1252 if (ret) {
1253 goto error_snapshot_output;
1254 }
1255 } else {
1256 if (output.control_uri) {
1257 ret = lttng_snapshot_output_set_ctrl_url(output.control_uri,
1258 snapshot_output);
1259 if (ret) {
1260 goto error_snapshot_output;
1261 }
1262 }
1263
1264 if (output.data_uri) {
1265 ret = lttng_snapshot_output_set_data_url(output.data_uri,
1266 snapshot_output);
1267 if (ret) {
1268 goto error_snapshot_output;
1269 }
1270 }
1271 }
1272
1273 ret = lttng_snapshot_add_output(session_name, snapshot_output);
1274error_snapshot_output:
1275 free(name);
1276 free(output.path);
1277 free(output.control_uri);
1278 free(output.data_uri);
1279 lttng_snapshot_output_destroy(snapshot_output);
1280 if (ret) {
1281 goto end;
1282 }
1283 }
1284end:
1285 return ret;
1286}
1287
1288static
1289int create_session(const char *name,
1290 struct lttng_domain *kernel_domain,
1291 struct lttng_domain *ust_domain,
1292 struct lttng_domain *jul_domain,
5cdb6027 1293 struct lttng_domain *log4j_domain,
dcf266c0
JG
1294 xmlNodePtr output_node,
1295 uint64_t live_timer_interval)
1296{
1297 int ret;
1298 struct consumer_output output = { 0 };
1299 xmlNodePtr consumer_output_node;
1300
1301 assert(name);
dcf266c0
JG
1302
1303 if (output_node) {
1304 consumer_output_node = xmlFirstElementChild(output_node);
1305 if (!consumer_output_node) {
1306 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1307 goto end;
1308 }
1309
1310 if (strcmp((const char *) consumer_output_node->name,
1311 config_element_consumer_output)) {
1312 WARN("Invalid output type, expected %s node",
1313 config_element_consumer_output);
1314 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1315 goto end;
1316 }
1317
1318 ret = process_consumer_output(consumer_output_node, &output);
1319 if (ret) {
1320 goto end;
1321 }
1322 }
1323
1324 if (live_timer_interval != UINT64_MAX &&
1325 !output.control_uri && !output.data_uri) {
1326 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1327 goto end;
1328 }
1329
1330 if (output.control_uri || output.data_uri) {
1331 int i;
1332 struct lttng_domain *domain;
1333 struct lttng_domain *domains[] =
c8c5f7ce 1334 { kernel_domain, ust_domain, jul_domain, log4j_domain };
dcf266c0
JG
1335
1336 /* network destination */
1337 if (live_timer_interval && live_timer_interval != UINT64_MAX) {
b664f89a
DG
1338 /*
1339 * URLs are provided for sure since the test above make sure that
1340 * with a live timer the data and control URIs are provided. So,
1341 * NULL is passed here and will be set right after.
1342 */
1343 ret = lttng_create_session_live(name, NULL, live_timer_interval);
dcf266c0
JG
1344 } else {
1345 ret = lttng_create_session(name, NULL);
1346 }
1347 if (ret) {
1348 goto end;
1349 }
1350
301423df 1351 for (i = 0; i < (sizeof(domains) / sizeof(domains[0])); i++) {
dcf266c0
JG
1352 domain = domains[i];
1353 if (!domain) {
1354 continue;
1355 }
1356
1357 ret = create_session_net_output(name, domain, output.control_uri,
1358 output.data_uri);
1359 if (ret) {
1360 goto end;
1361 }
1362 }
1363 } else {
1364 /* either local output or no output */
1365 ret = lttng_create_session(name, output.path);
1366 if (ret) {
1367 goto end;
1368 }
1369 }
1370end:
1371 free(output.path);
1372 free(output.control_uri);
1373 free(output.data_uri);
1374 return ret;
1375}
1376static
1377int process_probe_attribute_node(xmlNodePtr probe_attribute_node,
1378 struct lttng_event_probe_attr *attr)
1379{
1380 int ret;
1381
1382 assert(probe_attribute_node);
1383 assert(attr);
1384
1385 if (!strcmp((const char *) probe_attribute_node->name,
1386 config_element_address)) {
1387 xmlChar *content;
1388 uint64_t addr = 0;
1389
1390 /* addr */
1391 content = xmlNodeGetContent(probe_attribute_node);
1392 if (!content) {
1393 ret = -LTTNG_ERR_NOMEM;
1394 goto end;
1395 }
1396
1397 ret = parse_uint(content, &addr);
1398 free(content);
1399 if (ret) {
1400 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1401 goto end;
1402 }
1403
1404 attr->addr = addr;
1405 } else if (!strcmp((const char *) probe_attribute_node->name,
1406 config_element_offset)) {
1407 xmlChar *content;
1408 uint64_t offset = 0;
1409
1410 /* offset */
1411 content = xmlNodeGetContent(probe_attribute_node);
1412 if (!content) {
1413 ret = -LTTNG_ERR_NOMEM;
1414 goto end;
1415 }
1416
1417 ret = parse_uint(content, &offset);
1418 free(content);
1419 if (ret) {
1420 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1421 goto end;
1422 }
1423
1424 attr->offset = offset;
1425 } else if (!strcmp((const char *) probe_attribute_node->name,
1426 config_element_symbol_name)) {
1427 xmlChar *content;
1428 size_t name_len;
1429
1430 /* symbol_name */
1431 content = xmlNodeGetContent(probe_attribute_node);
1432 if (!content) {
1433 ret = -LTTNG_ERR_NOMEM;
1434 goto end;
1435 }
1436
1437 name_len = strlen((char *) content);
1438 if (name_len >= LTTNG_SYMBOL_NAME_LEN) {
1439 WARN("symbol_name too long.");
1440 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1441 free(content);
1442 goto end;
1443 }
1444
1445 strncpy(attr->symbol_name, (const char *) content, name_len);
1446 free(content);
1447 }
1448 ret = 0;
1449end:
1450 return ret;
1451}
1452
1453static
1454int process_event_node(xmlNodePtr event_node, struct lttng_handle *handle,
1455 const char *channel_name)
1456{
1457 int ret, i;
1458 xmlNodePtr node;
1459 struct lttng_event event;
1460 char **exclusions = NULL;
1461 unsigned long exclusion_count = 0;
1462 char *filter_expression = NULL;
1463
1464 assert(event_node);
1465 assert(handle);
1466 assert(channel_name);
1467
1468 memset(&event, 0, sizeof(event));
1469
f40eba3d
JG
1470 /* Initialize default log level which varies by domain */
1471 switch (handle->domain.type)
1472 {
1473 case LTTNG_DOMAIN_JUL:
1474 event.loglevel = LTTNG_LOGLEVEL_JUL_ALL;
1475 break;
1476 case LTTNG_DOMAIN_LOG4J:
1477 event.loglevel = LTTNG_LOGLEVEL_LOG4J_ALL;
1478 break;
1479 case LTTNG_DOMAIN_PYTHON:
1480 event.loglevel = LTTNG_LOGLEVEL_PYTHON_DEBUG;
1481 break;
1482 case LTTNG_DOMAIN_UST:
1483 case LTTNG_DOMAIN_KERNEL:
1484 event.loglevel = LTTNG_LOGLEVEL_DEBUG;
1485 break;
1486 default:
1487 assert(0);
1488 }
1489
dcf266c0
JG
1490 for (node = xmlFirstElementChild(event_node); node;
1491 node = xmlNextElementSibling(node)) {
1492 if (!strcmp((const char *) node->name, config_element_name)) {
1493 xmlChar *content;
1494 size_t name_len;
1495
1496 /* name */
1497 content = xmlNodeGetContent(node);
1498 if (!content) {
1499 ret = -LTTNG_ERR_NOMEM;
1500 goto end;
1501 }
1502
1503 name_len = strlen((char *) content);
1504 if (name_len >= LTTNG_SYMBOL_NAME_LEN) {
1505 WARN("Channel name too long.");
1506 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1507 free(content);
1508 goto end;
1509 }
1510
1511 strncpy(event.name, (const char *) content, name_len);
1512 free(content);
1513 } else if (!strcmp((const char *) node->name,
1514 config_element_enabled)) {
1515 xmlChar *content = xmlNodeGetContent(node);
1516
1517 /* enabled */
1518 if (!content) {
1519 ret = -LTTNG_ERR_NOMEM;
1520 goto end;
1521 }
1522
1523 ret = parse_bool(content, &event.enabled);
1524 free(content);
1525 if (ret) {
1526 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1527 goto end;
1528 }
1529 } else if (!strcmp((const char *) node->name,
1530 config_element_type)) {
1531 xmlChar *content = xmlNodeGetContent(node);
1532
1533 /* type */
1534 if (!content) {
1535 ret = -LTTNG_ERR_NOMEM;
1536 goto end;
1537 }
1538
1539 ret = get_event_type(content);
1540 free(content);
1541 if (ret < 0) {
1542 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1543 goto end;
1544 }
1545
1546 event.type = ret;
1547 } else if (!strcmp((const char *) node->name,
1548 config_element_loglevel_type)) {
1549 xmlChar *content = xmlNodeGetContent(node);
1550
1551 /* loglevel_type */
1552 if (!content) {
1553 ret = -LTTNG_ERR_NOMEM;
1554 goto end;
1555 }
1556
1557 ret = get_loglevel_type(content);
1558 free(content);
1559 if (ret < 0) {
1560 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1561 goto end;
1562 }
1563
1564 event.loglevel_type = ret;
1565 } else if (!strcmp((const char *) node->name,
1566 config_element_loglevel)) {
1567 xmlChar *content;
1568 int64_t loglevel = 0;
1569
1570 /* loglevel */
1571 content = xmlNodeGetContent(node);
1572 if (!content) {
1573 ret = -LTTNG_ERR_NOMEM;
1574 goto end;
1575 }
1576
1577 ret = parse_int(content, &loglevel);
1578 free(content);
1579 if (ret) {
1580 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1581 goto end;
1582 }
1583
1584 if (loglevel > INT_MAX || loglevel < INT_MIN) {
1585 WARN("loglevel out of range.");
1586 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1587 goto end;
1588 }
1589
1590 event.loglevel = loglevel;
1591 } else if (!strcmp((const char *) node->name,
1592 config_element_filter)) {
1593 xmlChar *content =
1594 xmlNodeGetContent(node);
1595
1596 /* filter */
1597 if (!content) {
1598 ret = -LTTNG_ERR_NOMEM;
1599 goto end;
1600 }
1601
1602 filter_expression = strdup((char *) content);
1603 free(content);
1604 if (!filter_expression) {
1605 ret = -LTTNG_ERR_NOMEM;
1606 goto end;
1607 }
1608 } else if (!strcmp((const char *) node->name,
1609 config_element_exclusions)) {
1610 xmlNodePtr exclusion_node;
1611 int exclusion_index = 0;
1612
1613 /* exclusions */
1614 if (exclusions) {
1615 /*
1616 * Exclusions has already been initialized,
1617 * invalid file.
1618 */
1619 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1620 goto end;
1621 }
1622
1623 exclusion_count = xmlChildElementCount(node);
1624 if (!exclusion_count) {
1625 continue;
1626 }
1627
1628 exclusions = zmalloc(exclusion_count * sizeof(char *));
1629 if (!exclusions) {
1630 exclusion_count = 0;
1631 ret = -LTTNG_ERR_NOMEM;
1632 goto end;
1633 }
1634
1635 for (exclusion_node = xmlFirstElementChild(node); exclusion_node;
1636 exclusion_node = xmlNextElementSibling(exclusion_node)) {
1637 xmlChar *content =
1638 xmlNodeGetContent(exclusion_node);
1639
1640 if (!content) {
1641 ret = -LTTNG_ERR_NOMEM;
1642 goto end;
1643 }
1644
1645 exclusions[exclusion_index] = strdup((const char *) content);
1646 free(content);
1647 if (!exclusions[exclusion_index]) {
1648 ret = -LTTNG_ERR_NOMEM;
1649 goto end;
1650 }
1651 exclusion_index++;
1652 }
1653
1654 event.exclusion = 1;
1655 } else if (!strcmp((const char *) node->name,
1656 config_element_attributes)) {
1657 xmlNodePtr attribute_node = xmlFirstElementChild(node);
1658
1659 /* attributes */
1660 if (!attribute_node) {
1661 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1662 goto end;
1663 }
1664
1665 if (!strcmp((const char *) node->name,
1666 config_element_probe_attributes)) {
1667 xmlNodePtr probe_attribute_node;
1668
1669 /* probe_attributes */
1670 for (probe_attribute_node =
1671 xmlFirstElementChild(attribute_node); probe_attribute_node;
1672 probe_attribute_node = xmlNextElementSibling(
1673 probe_attribute_node)) {
1674
1675 ret = process_probe_attribute_node(probe_attribute_node,
1676 &event.attr.probe);
1677 if (ret) {
1678 goto end;
1679 }
1680 }
1681 } else {
1682 size_t sym_len;
1683 xmlChar *content;
1684 xmlNodePtr symbol_node = xmlFirstElementChild(attribute_node);
1685
1686 /* function_attributes */
1687 content = xmlNodeGetContent(symbol_node);
1688 if (!content) {
1689 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1690 goto end;
1691 }
1692
1693 sym_len = strlen((char *) content);
1694 if (sym_len >= LTTNG_SYMBOL_NAME_LEN) {
1695 WARN("Function name too long.");
1696 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1697 free(content);
1698 goto end;
1699 }
1700
1701 strncpy(event.attr.ftrace.symbol_name, (char *) content,
1702 sym_len);
1703 free(content);
1704 }
1705 }
1706 }
1707
1708 ret = lttng_enable_event_with_exclusions(handle, &event, channel_name,
1709 filter_expression, exclusion_count, exclusions);
065321e9
JG
1710 if (ret) {
1711 goto end;
1712 }
1713
1714 if (!event.enabled) {
1715 /*
1716 * Note that we should use lttng_disable_event_ext() (2.6+) to
1717 * eliminate the risk of clashing on events of the same
1718 * name (with different event types and loglevels).
1719 *
1720 * Unfortunately, lttng_disable_event_ext() only performs a
1721 * match on the name and event type and errors out if any other
1722 * event attribute is not set to its default value.
1723 *
1724 * This will disable all events that match this name.
1725 */
1726 ret = lttng_disable_event(handle, event.name, channel_name);
1727 }
dcf266c0
JG
1728end:
1729 for (i = 0; i < exclusion_count; i++) {
1730 free(exclusions[i]);
1731 }
1732
1733 free(exclusions);
1734 free(filter_expression);
1735 return ret;
1736}
1737
1738static
1739int process_events_node(xmlNodePtr events_node, struct lttng_handle *handle,
1740 const char *channel_name)
1741{
1742 int ret = 0;
1743 xmlNodePtr node;
1744
1745 assert(events_node);
1746 assert(handle);
1747 assert(channel_name);
1748
1749 for (node = xmlFirstElementChild(events_node); node;
1750 node = xmlNextElementSibling(node)) {
1751 ret = process_event_node(node, handle, channel_name);
1752 if (ret) {
1753 goto end;
1754 }
1755 }
1756end:
1757 return ret;
1758}
1759
1760static
1761int process_channel_attr_node(xmlNodePtr attr_node,
1762 struct lttng_channel *channel, xmlNodePtr *contexts_node,
1763 xmlNodePtr *events_node)
1764{
1765 int ret;
1766
1767 assert(attr_node);
1768 assert(channel);
1769 assert(contexts_node);
1770 assert(events_node);
1771
1772 if (!strcmp((const char *) attr_node->name, config_element_name)) {
1773 xmlChar *content;
1774 size_t name_len;
1775
1776 /* name */
1777 content = xmlNodeGetContent(attr_node);
1778 if (!content) {
1779 ret = -LTTNG_ERR_NOMEM;
1780 goto end;
1781 }
1782
1783 name_len = strlen((char *) content);
1784 if (name_len >= LTTNG_SYMBOL_NAME_LEN) {
1785 WARN("Channel name too long.");
1786 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1787 free(content);
1788 goto end;
1789 }
1790
1791 strncpy(channel->name, (const char *) content, name_len);
1792 free(content);
1793 } else if (!strcmp((const char *) attr_node->name,
1794 config_element_enabled)) {
1795 xmlChar *content;
1796 int enabled;
1797
1798 /* enabled */
1799 content = xmlNodeGetContent(attr_node);
1800 if (!content) {
1801 ret = -LTTNG_ERR_NOMEM;
1802 goto end;
1803 }
1804
1805 ret = parse_bool(content, &enabled);
1806 free(content);
1807 if (ret) {
1808 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1809 goto end;
1810 }
1811
1812 channel->enabled = enabled;
1813 } else if (!strcmp((const char *) attr_node->name,
1814 config_element_overwrite_mode)) {
1815 xmlChar *content;
1816
1817 /* overwrite_mode */
1818 content = xmlNodeGetContent(attr_node);
1819 if (!content) {
1820 ret = -LTTNG_ERR_NOMEM;
1821 goto end;
1822 }
1823
1824 ret = get_overwrite_mode(content);
1825 free(content);
1826 if (ret < 0) {
1827 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1828 goto end;
1829 }
1830
1831 channel->attr.overwrite = ret;
1832 } else if (!strcmp((const char *) attr_node->name,
1833 config_element_subbuf_size)) {
1834 xmlChar *content;
1835
1836 /* subbuffer_size */
1837 content = xmlNodeGetContent(attr_node);
1838 if (!content) {
1839 ret = -LTTNG_ERR_NOMEM;
1840 goto end;
1841 }
1842
1843 ret = parse_uint(content, &channel->attr.subbuf_size);
1844 free(content);
1845 if (ret) {
1846 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1847 goto end;
1848 }
1849 } else if (!strcmp((const char *) attr_node->name,
1850 config_element_num_subbuf)) {
1851 xmlChar *content;
1852
1853 /* subbuffer_count */
1854 content = xmlNodeGetContent(attr_node);
1855 if (!content) {
1856 ret = -LTTNG_ERR_NOMEM;
1857 goto end;
1858 }
1859
1860 ret = parse_uint(content, &channel->attr.num_subbuf);
1861 free(content);
1862 if (ret) {
1863 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1864 goto end;
1865 }
1866 } else if (!strcmp((const char *) attr_node->name,
1867 config_element_switch_timer_interval)) {
1868 xmlChar *content;
1869 uint64_t switch_timer_interval = 0;
1870
1871 /* switch_timer_interval */
1872 content = xmlNodeGetContent(attr_node);
1873 if (!content) {
1874 ret = -LTTNG_ERR_NOMEM;
1875 goto end;
1876 }
1877
1878 ret = parse_uint(content, &switch_timer_interval);
1879 free(content);
1880 if (ret) {
1881 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1882 goto end;
1883 }
1884
1885 if (switch_timer_interval > UINT_MAX) {
1886 WARN("switch_timer_interval out of range.");
1887 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1888 goto end;
1889 }
1890
1891 channel->attr.switch_timer_interval =
1892 switch_timer_interval;
1893 } else if (!strcmp((const char *) attr_node->name,
1894 config_element_read_timer_interval)) {
1895 xmlChar *content;
1896 uint64_t read_timer_interval = 0;
1897
1898 /* read_timer_interval */
1899 content = xmlNodeGetContent(attr_node);
1900 if (!content) {
1901 ret = -LTTNG_ERR_NOMEM;
1902 goto end;
1903 }
1904
1905 ret = parse_uint(content, &read_timer_interval);
1906 free(content);
1907 if (ret) {
1908 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1909 goto end;
1910 }
1911
1912 if (read_timer_interval > UINT_MAX) {
1913 WARN("read_timer_interval out of range.");
1914 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1915 goto end;
1916 }
1917
1918 channel->attr.read_timer_interval =
1919 read_timer_interval;
1920 } else if (!strcmp((const char *) attr_node->name,
1921 config_element_output_type)) {
1922 xmlChar *content;
1923
1924 /* output_type */
1925 content = xmlNodeGetContent(attr_node);
1926 if (!content) {
1927 ret = -LTTNG_ERR_NOMEM;
1928 goto end;
1929 }
1930
1931 ret = get_output_type(content);
1932 free(content);
1933 if (ret < 0) {
1934 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1935 goto end;
1936 }
1937
1938 channel->attr.output = ret;
1939 } else if (!strcmp((const char *) attr_node->name,
1940 config_element_tracefile_size)) {
1941 xmlChar *content;
1942
1943 /* tracefile_size */
1944 content = xmlNodeGetContent(attr_node);
1945 if (!content) {
1946 ret = -LTTNG_ERR_NOMEM;
1947 goto end;
1948 }
1949
1950 ret = parse_uint(content, &channel->attr.tracefile_size);
1951 free(content);
1952 if (ret) {
1953 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1954 goto end;
1955 }
1956 } else if (!strcmp((const char *) attr_node->name,
1957 config_element_tracefile_count)) {
1958 xmlChar *content;
1959
1960 /* tracefile_count */
1961 content = xmlNodeGetContent(attr_node);
1962 if (!content) {
1963 ret = -LTTNG_ERR_NOMEM;
1964 goto end;
1965 }
1966
1967 ret = parse_uint(content, &channel->attr.tracefile_count);
1968 free(content);
1969 if (ret) {
1970 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1971 goto end;
1972 }
1973 } else if (!strcmp((const char *) attr_node->name,
1974 config_element_live_timer_interval)) {
1975 xmlChar *content;
1976 uint64_t live_timer_interval = 0;
1977
1978 /* live_timer_interval */
1979 content = xmlNodeGetContent(attr_node);
1980 if (!content) {
1981 ret = -LTTNG_ERR_NOMEM;
1982 goto end;
1983 }
1984
1985 ret = parse_uint(content, &live_timer_interval);
1986 free(content);
1987 if (ret) {
1988 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1989 goto end;
1990 }
1991
1992 if (live_timer_interval > UINT_MAX) {
1993 WARN("live_timer_interval out of range.");
1994 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1995 goto end;
1996 }
1997
1998 channel->attr.live_timer_interval =
1999 live_timer_interval;
2000 } else if (!strcmp((const char *) attr_node->name,
2001 config_element_events)) {
2002 /* events */
2003 *events_node = attr_node;
2004 } else {
2005 /* contexts */
2006 *contexts_node = attr_node;
2007 }
2008 ret = 0;
2009end:
2010 return ret;
2011}
2012
2013static
2014int process_context_node(xmlNodePtr context_node,
2015 struct lttng_handle *handle, const char *channel_name)
2016{
2017 int ret;
2018 struct lttng_event_context context;
2019 xmlNodePtr context_child_node = xmlFirstElementChild(context_node);
2020
2021 assert(handle);
2022 assert(channel_name);
2023
2024 if (!context_child_node) {
2025 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2026 goto end;
2027 }
2028
2029 memset(&context, 0, sizeof(context));
2030
2031 if (!strcmp((const char *) context_child_node->name,
2032 config_element_type)) {
2033 /* type */
2034 xmlChar *content = xmlNodeGetContent(context_child_node);
045fc617 2035
dcf266c0
JG
2036 if (!content) {
2037 ret = -LTTNG_ERR_NOMEM;
2038 goto end;
2039 }
2040
2041 ret = get_context_type(content);
2042 free(content);
2043 if (ret < 0) {
2044 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2045 goto end;
2046 }
2047
2048 context.ctx = ret;
045fc617
JG
2049 } else if (!strcmp((const char *) context_child_node->name,
2050 config_element_context_perf)) {
2051 /* perf */
dcf266c0
JG
2052 xmlNodePtr perf_attr_node;
2053
14ce5bd8
JG
2054 context.ctx = handle->domain.type == LTTNG_DOMAIN_KERNEL ?
2055 LTTNG_EVENT_CONTEXT_PERF_CPU_COUNTER :
2056 LTTNG_EVENT_CONTEXT_PERF_THREAD_COUNTER;
dcf266c0
JG
2057 for (perf_attr_node = xmlFirstElementChild(context_child_node);
2058 perf_attr_node; perf_attr_node =
2059 xmlNextElementSibling(perf_attr_node)) {
2060 if (!strcmp((const char *) perf_attr_node->name,
2061 config_element_type)) {
2062 xmlChar *content;
2063 uint64_t type = 0;
2064
2065 /* type */
2066 content = xmlNodeGetContent(perf_attr_node);
2067 if (!content) {
2068 ret = -LTTNG_ERR_NOMEM;
2069 goto end;
2070 }
2071
2072 ret = parse_uint(content, &type);
2073 free(content);
2074 if (ret) {
2075 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2076 goto end;
2077 }
2078
2079 if (type > UINT32_MAX) {
2080 WARN("perf context type out of range.");
2081 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2082 goto end;
2083 }
2084
2085 context.u.perf_counter.type = type;
2086 } else if (!strcmp((const char *) perf_attr_node->name,
2087 config_element_config)) {
2088 xmlChar *content;
2089 uint64_t config = 0;
2090
2091 /* config */
2092 content = xmlNodeGetContent(perf_attr_node);
2093 if (!content) {
2094 ret = -LTTNG_ERR_NOMEM;
2095 goto end;
2096 }
2097
2098 ret = parse_uint(content, &config);
2099 free(content);
2100 if (ret) {
2101 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2102 goto end;
2103 }
2104
2105 context.u.perf_counter.config = config;
2106 } else if (!strcmp((const char *) perf_attr_node->name,
2107 config_element_name)) {
2108 xmlChar *content;
2109 size_t name_len;
2110
2111 /* name */
2112 content = xmlNodeGetContent(perf_attr_node);
2113 if (!content) {
2114 ret = -LTTNG_ERR_NOMEM;
2115 goto end;
2116 }
2117
2118 name_len = strlen((char *) content);
2119 if (name_len >= LTTNG_SYMBOL_NAME_LEN) {
2120 WARN("perf context name too long.");
2121 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2122 free(content);
2123 goto end;
2124 }
2125
2126 strncpy(context.u.perf_counter.name, (const char *) content,
2127 name_len);
2128 free(content);
2129 }
2130 }
045fc617
JG
2131 } else if (!strcmp((const char *) context_child_node->name,
2132 config_element_context_app)) {
2133 /* application context */
2134 xmlNodePtr app_ctx_node;
2135
2136 context.ctx = LTTNG_EVENT_CONTEXT_APP_CONTEXT;
2137 for (app_ctx_node = xmlFirstElementChild(context_child_node);
2138 app_ctx_node; app_ctx_node =
2139 xmlNextElementSibling(app_ctx_node)) {
2140 xmlChar *content;
2141 char **target = strcmp(
2142 (const char *) app_ctx_node->name,
2143 config_element_context_app_provider_name) == 0 ?
2144 &context.u.app_ctx.provider_name :
2145 &context.u.app_ctx.ctx_name;
2146
2147 content = xmlNodeGetContent(app_ctx_node);
2148 if (!content) {
2149 ret = -LTTNG_ERR_NOMEM;
2150 goto end;
2151 }
2152
2153 *target = (char *) content;
2154 }
2155 } else {
2156 /* Unrecognized context type */
2157 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2158 goto end;
dcf266c0
JG
2159 }
2160
2161 ret = lttng_add_context(handle, &context, NULL, channel_name);
045fc617
JG
2162 if (context.ctx == LTTNG_EVENT_CONTEXT_APP_CONTEXT) {
2163 free(context.u.app_ctx.provider_name);
2164 free(context.u.app_ctx.ctx_name);
2165 }
dcf266c0
JG
2166end:
2167 return ret;
2168}
2169
2170static
2171int process_contexts_node(xmlNodePtr contexts_node,
2172 struct lttng_handle *handle, const char *channel_name)
2173{
2174 int ret = 0;
2175 xmlNodePtr context_node;
2176
2177 for (context_node = xmlFirstElementChild(contexts_node); context_node;
2178 context_node = xmlNextElementSibling(context_node)) {
2179 ret = process_context_node(context_node, handle, channel_name);
2180 if (ret) {
2181 goto end;
2182 }
2183 }
2184end:
2185 return ret;
2186}
2187
847a5916
JR
2188static
2189int process_pid_tracker_node(xmlNodePtr pid_tracker_node,
2190 struct lttng_handle *handle)
2191{
dd49e13f 2192 int ret = 0, child;
847a5916
JR
2193 xmlNodePtr targets_node = NULL;
2194 xmlNodePtr node;
2195
2196 assert(handle);
2197 assert(pid_tracker_node);
2198 /* get the targets node */
2199 for (node = xmlFirstElementChild(pid_tracker_node); node;
2200 node = xmlNextElementSibling(node)) {
2201 if (!strcmp((const char *) node->name,
2202 config_element_targets)) {
2203 targets_node = node;
2204 break;
2205 }
2206 }
2207
2208 if (!targets_node) {
2209 ret = LTTNG_ERR_INVALID;
2210 goto end;
2211 }
2212
2213 /* Go through all pid_target node */
2214 child = xmlChildElementCount(targets_node);
2215 if (child == 0) {
2216 /* The session is explicitly set to target nothing. */
2217 ret = lttng_untrack_pid(handle, -1);
2218 if (ret) {
2219 goto end;
2220 }
2221 }
2222 for (node = xmlFirstElementChild(targets_node); node;
2223 node = xmlNextElementSibling(node)) {
2224 xmlNodePtr pid_target_node = node;
2225
2226 /* get pid node and track it */
2227 for (node = xmlFirstElementChild(pid_target_node); node;
2228 node = xmlNextElementSibling(node)) {
2229 if (!strcmp((const char *) node->name,
2230 config_element_pid)) {
2231 int64_t pid;
2232 xmlChar *content = NULL;
2233
2234 content = xmlNodeGetContent(node);
2235 if (!content) {
2236 ret = LTTNG_ERR_LOAD_INVALID_CONFIG;
2237 goto end;
2238 }
2239
2240 ret = parse_int(content, &pid);
2241 free(content);
2242 if (ret) {
2243 ret = LTTNG_ERR_LOAD_INVALID_CONFIG;
2244 goto end;
2245 }
2246
2247 ret = lttng_track_pid(handle, (int) pid);
2248 if (ret) {
2249 goto end;
2250 }
2251 }
2252 }
2253 node = pid_target_node;
2254 }
2255
2256end:
2257 return ret;
2258}
2259
2260
dcf266c0
JG
2261static
2262int process_domain_node(xmlNodePtr domain_node, const char *session_name)
2263{
2264 int ret;
2265 struct lttng_domain domain = { 0 };
2266 struct lttng_handle *handle = NULL;
2267 xmlNodePtr channels_node = NULL;
847a5916
JR
2268 xmlNodePtr trackers_node = NULL;
2269 xmlNodePtr pid_tracker_node = NULL;
dcf266c0
JG
2270 xmlNodePtr node;
2271
2272 assert(session_name);
2273
2274 ret = init_domain(domain_node, &domain);
2275 if (ret) {
2276 goto end;
2277 }
2278
2279 handle = lttng_create_handle(session_name, &domain);
2280 if (!handle) {
2281 ret = -LTTNG_ERR_NOMEM;
2282 goto end;
2283 }
2284
2285 /* get the channels node */
2286 for (node = xmlFirstElementChild(domain_node); node;
2287 node = xmlNextElementSibling(node)) {
2288 if (!strcmp((const char *) node->name,
2289 config_element_channels)) {
2290 channels_node = node;
2291 break;
2292 }
2293 }
2294
2295 if (!channels_node) {
2296 goto end;
2297 }
2298
2299 /* create all channels */
2300 for (node = xmlFirstElementChild(channels_node); node;
2301 node = xmlNextElementSibling(node)) {
2302 struct lttng_channel channel;
2303 xmlNodePtr contexts_node = NULL;
2304 xmlNodePtr events_node = NULL;
2305 xmlNodePtr channel_attr_node;
2306
2307 memset(&channel, 0, sizeof(channel));
2308 lttng_channel_set_default_attr(&domain, &channel.attr);
2309
2310 for (channel_attr_node = xmlFirstElementChild(node);
2311 channel_attr_node; channel_attr_node =
2312 xmlNextElementSibling(channel_attr_node)) {
2313 ret = process_channel_attr_node(channel_attr_node,
2314 &channel, &contexts_node, &events_node);
2315 if (ret) {
2316 goto end;
2317 }
2318 }
2319
2320 ret = lttng_enable_channel(handle, &channel);
2321 if (ret < 0) {
2322 goto end;
2323 }
2324
2325 ret = process_events_node(events_node, handle, channel.name);
2326 if (ret) {
2327 goto end;
2328 }
2329
2330 ret = process_contexts_node(contexts_node, handle,
2331 channel.name);
2332 if (ret) {
2333 goto end;
2334 }
2335 }
847a5916
JR
2336
2337 /* get the trackers node */
2338 for (node = xmlFirstElementChild(domain_node); node;
2339 node = xmlNextElementSibling(node)) {
2340 if (!strcmp((const char *) node->name,
2341 config_element_trackers)) {
2342 trackers_node = node;
2343 break;
2344 }
2345 }
2346
2347 if (!trackers_node) {
2348 goto end;
2349 }
2350
2351 for (node = xmlFirstElementChild(trackers_node); node;
2352 node = xmlNextElementSibling(node)) {
2353 if (!strcmp((const char *)node->name,config_element_pid_tracker)) {
2354 pid_tracker_node = node;
2355 ret = process_pid_tracker_node(pid_tracker_node, handle);
2356 if (ret) {
2357 goto end;
2358 }
2359 }
2360 }
2361
2362 if (!pid_tracker_node) {
2363 lttng_track_pid(handle, -1);
2364 }
2365
dcf266c0
JG
2366end:
2367 lttng_destroy_handle(handle);
2368 return ret;
2369}
2370
2371static
2372int process_session_node(xmlNodePtr session_node, const char *session_name,
2373 int override)
2374{
2375 int ret, started = -1, snapshot_mode = -1;
2376 uint64_t live_timer_interval = UINT64_MAX;
d324faf7 2377 xmlChar *name = NULL;
9e7c9f56 2378 xmlChar *shm_path = NULL;
dcf266c0
JG
2379 xmlNodePtr domains_node = NULL;
2380 xmlNodePtr output_node = NULL;
2381 xmlNodePtr node;
2382 struct lttng_domain *kernel_domain = NULL;
2383 struct lttng_domain *ust_domain = NULL;
2384 struct lttng_domain *jul_domain = NULL;
5cdb6027 2385 struct lttng_domain *log4j_domain = NULL;
0e115563 2386 struct lttng_domain *python_domain = NULL;
dcf266c0
JG
2387
2388 for (node = xmlFirstElementChild(session_node); node;
2389 node = xmlNextElementSibling(node)) {
2390 if (!name && !strcmp((const char *) node->name,
2391 config_element_name)) {
2392 /* name */
2393 xmlChar *node_content = xmlNodeGetContent(node);
2394 if (!node_content) {
2395 ret = -LTTNG_ERR_NOMEM;
c2da8cde 2396 goto error;
dcf266c0
JG
2397 }
2398
d324faf7 2399 name = node_content;
dcf266c0
JG
2400 } else if (!domains_node && !strcmp((const char *) node->name,
2401 config_element_domains)) {
2402 /* domains */
2403 domains_node = node;
2404 } else if (started == -1 && !strcmp((const char *) node->name,
2405 config_element_started)) {
2406 /* started */
2407 xmlChar *node_content = xmlNodeGetContent(node);
2408 if (!node_content) {
2409 ret = -LTTNG_ERR_NOMEM;
c2da8cde 2410 goto error;
dcf266c0
JG
2411 }
2412
2413 ret = parse_bool(node_content, &started);
2414 free(node_content);
2415 if (ret) {
2416 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
c2da8cde 2417 goto error;
dcf266c0
JG
2418 }
2419 } else if (!output_node && !strcmp((const char *) node->name,
2420 config_element_output)) {
2421 /* output */
2422 output_node = node;
9e7c9f56
JR
2423 } else if (!shm_path && !strcmp((const char *) node->name,
2424 config_element_shared_memory_path)) {
2425 /* shared memory path */
2426 xmlChar *node_content = xmlNodeGetContent(node);
2427 if (!node_content) {
2428 ret = -LTTNG_ERR_NOMEM;
2429 goto error;
2430 }
2431
2432 shm_path = node_content;
dcf266c0
JG
2433 } else {
2434 /* attributes, snapshot_mode or live_timer_interval */
2435 xmlNodePtr attributes_child =
2436 xmlFirstElementChild(node);
2437
2438 if (!strcmp((const char *) attributes_child->name,
2439 config_element_snapshot_mode)) {
2440 /* snapshot_mode */
2441 xmlChar *snapshot_mode_content =
2442 xmlNodeGetContent(attributes_child);
2443 if (!snapshot_mode_content) {
2444 ret = -LTTNG_ERR_NOMEM;
c2da8cde 2445 goto error;
dcf266c0
JG
2446 }
2447
2448 ret = parse_bool(snapshot_mode_content, &snapshot_mode);
2449 free(snapshot_mode_content);
2450 if (ret) {
2451 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
c2da8cde 2452 goto error;
dcf266c0
JG
2453 }
2454 } else {
2455 /* live_timer_interval */
2456 xmlChar *timer_interval_content =
2457 xmlNodeGetContent(attributes_child);
2458 if (!timer_interval_content) {
2459 ret = -LTTNG_ERR_NOMEM;
c2da8cde 2460 goto error;
dcf266c0
JG
2461 }
2462
2463 ret = parse_uint(timer_interval_content, &live_timer_interval);
2464 free(timer_interval_content);
2465 if (ret) {
2466 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
c2da8cde 2467 goto error;
dcf266c0
JG
2468 }
2469 }
2470 }
2471 }
2472
2473 if (!name) {
2474 /* Mandatory attribute, as defined in the session XSD */
2475 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
c2da8cde 2476 goto error;
dcf266c0
JG
2477 }
2478
d324faf7 2479 if (session_name && strcmp((char *) name, session_name)) {
dcf266c0 2480 /* This is not the session we are looking for */
c2da8cde
DG
2481 ret = -LTTNG_ERR_NO_SESSION;
2482 goto error;
dcf266c0
JG
2483 }
2484
2485 /* Init domains to create the session handles */
2486 for (node = xmlFirstElementChild(domains_node); node;
2487 node = xmlNextElementSibling(node)) {
2488 struct lttng_domain *domain;
2489
2490 domain = zmalloc(sizeof(*domain));
2491 if (!domain) {
2492 ret = -LTTNG_ERR_NOMEM;
c2da8cde 2493 goto error;
dcf266c0
JG
2494 }
2495
2496 ret = init_domain(node, domain);
2497 if (ret) {
2498 goto domain_init_error;
2499 }
2500
2501 switch (domain->type) {
2502 case LTTNG_DOMAIN_KERNEL:
c33e6729
DG
2503 if (kernel_domain) {
2504 /* Same domain seen twice, invalid! */
2505 goto domain_init_error;
2506 }
dcf266c0
JG
2507 kernel_domain = domain;
2508 break;
2509 case LTTNG_DOMAIN_UST:
c33e6729
DG
2510 if (ust_domain) {
2511 /* Same domain seen twice, invalid! */
2512 goto domain_init_error;
2513 }
dcf266c0
JG
2514 ust_domain = domain;
2515 break;
2516 case LTTNG_DOMAIN_JUL:
c33e6729
DG
2517 if (jul_domain) {
2518 /* Same domain seen twice, invalid! */
2519 goto domain_init_error;
2520 }
dcf266c0
JG
2521 jul_domain = domain;
2522 break;
5cdb6027
DG
2523 case LTTNG_DOMAIN_LOG4J:
2524 if (log4j_domain) {
2525 /* Same domain seen twice, invalid! */
2526 goto domain_init_error;
2527 }
2528 log4j_domain = domain;
2529 break;
0e115563
DG
2530 case LTTNG_DOMAIN_PYTHON:
2531 if (python_domain) {
2532 /* Same domain seen twice, invalid! */
2533 goto domain_init_error;
2534 }
2535 python_domain = domain;
2536 break;
dcf266c0
JG
2537 default:
2538 WARN("Invalid domain type");
2539 goto domain_init_error;
2540 }
2541 continue;
2542domain_init_error:
2543 free(domain);
2544 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
c2da8cde 2545 goto error;
dcf266c0
JG
2546 }
2547
2548 if (override) {
2549 /* Destroy session if it exists */
d324faf7 2550 ret = lttng_destroy_session((const char *) name);
dcf266c0
JG
2551 if (ret && ret != -LTTNG_ERR_SESS_NOT_FOUND) {
2552 ERR("Failed to destroy existing session.");
c2da8cde 2553 goto error;
dcf266c0
JG
2554 }
2555 }
2556
2557 /* Create session type depending on output type */
2558 if (snapshot_mode && snapshot_mode != -1) {
d324faf7 2559 ret = create_snapshot_session((const char *) name, output_node);
dcf266c0
JG
2560 } else if (live_timer_interval &&
2561 live_timer_interval != UINT64_MAX) {
d324faf7
JG
2562 ret = create_session((const char *) name, kernel_domain,
2563 ust_domain, jul_domain, log4j_domain,
2564 output_node, live_timer_interval);
dcf266c0
JG
2565 } else {
2566 /* regular session */
d324faf7
JG
2567 ret = create_session((const char *) name, kernel_domain,
2568 ust_domain, jul_domain, log4j_domain,
2569 output_node, UINT64_MAX);
dcf266c0 2570 }
dcf266c0 2571 if (ret) {
c2da8cde 2572 goto error;
dcf266c0
JG
2573 }
2574
9e7c9f56
JR
2575 if (shm_path) {
2576 ret = lttng_set_session_shm_path((const char *) name,
d324faf7 2577 (const char *) shm_path);
9e7c9f56
JR
2578 if (ret) {
2579 goto error;
2580 }
2581 }
2582
dcf266c0
JG
2583 for (node = xmlFirstElementChild(domains_node); node;
2584 node = xmlNextElementSibling(node)) {
d324faf7 2585 ret = process_domain_node(node, (const char *) name);
dcf266c0
JG
2586 if (ret) {
2587 goto end;
2588 }
2589 }
2590
2591 if (started) {
d324faf7 2592 ret = lttng_start_tracing((const char *) name);
dcf266c0
JG
2593 if (ret) {
2594 goto end;
2595 }
2596 }
c2da8cde 2597
dcf266c0 2598end:
b2579dc1 2599 if (ret < 0) {
d324faf7
JG
2600 ERR("Failed to load session %s: %s", (const char *) name,
2601 lttng_strerror(ret));
2602 lttng_destroy_session((const char *) name);
b2579dc1
JG
2603 }
2604
c2da8cde 2605error:
dcf266c0
JG
2606 free(kernel_domain);
2607 free(ust_domain);
2608 free(jul_domain);
5cdb6027 2609 free(log4j_domain);
135a3893 2610 free(python_domain);
d324faf7 2611 xmlFree(name);
9e7c9f56 2612 xmlFree(shm_path);
dcf266c0
JG
2613 return ret;
2614}
2615
cf53c06d
DG
2616/*
2617 * Return 1 if the given path is readable by the current UID or 0 if not.
2618 * Return -1 if the path is EPERM.
2619 */
2620static int validate_file_read_creds(const char *path)
2621{
2622 int ret;
2623
2624 assert(path);
2625
2626 /* Can we read the file. */
2627 ret = access(path, R_OK);
2628 if (!ret) {
2629 goto valid;
2630 }
2631 if (errno == EACCES) {
2632 return -1;
2633 } else {
2634 /* Invalid. */
2635 return 0;
2636 }
2637valid:
2638 return 1;
2639}
2640
dcf266c0
JG
2641static
2642int load_session_from_file(const char *path, const char *session_name,
2643 struct session_config_validation_ctx *validation_ctx, int override)
2644{
2645 int ret, session_found = !session_name;
2646 xmlDocPtr doc = NULL;
2647 xmlNodePtr sessions_node;
2648 xmlNodePtr session_node;
dcf266c0
JG
2649
2650 assert(path);
2651 assert(validation_ctx);
2652
cf53c06d
DG
2653 ret = validate_file_read_creds(path);
2654 if (ret != 1) {
2655 if (ret == -1) {
2656 ret = -LTTNG_ERR_EPERM;
2657 } else {
2658 ret = -LTTNG_ERR_LOAD_SESSION_NOENT;
2659 }
dcf266c0
JG
2660 goto end;
2661 }
2662
2663 doc = xmlParseFile(path);
2664 if (!doc) {
2665 ret = -LTTNG_ERR_LOAD_IO_FAIL;
2666 goto end;
2667 }
2668
2669 ret = xmlSchemaValidateDoc(validation_ctx->schema_validation_ctx, doc);
2670 if (ret) {
2671 ERR("Session configuration file validation failed");
2672 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2673 goto end;
2674 }
2675
2676 sessions_node = xmlDocGetRootElement(doc);
2677 if (!sessions_node) {
2678 goto end;
2679 }
2680
2681 for (session_node = xmlFirstElementChild(sessions_node);
2682 session_node; session_node =
2683 xmlNextElementSibling(session_node)) {
2684 ret = process_session_node(session_node,
2685 session_name, override);
2686 if (session_name && ret == 0) {
2687 /* Target session found and loaded */
2688 session_found = 1;
2689 break;
2690 }
2691 }
2692end:
2693 xmlFreeDoc(doc);
2694 if (!ret) {
a96bc65d 2695 ret = session_found ? 0 : -LTTNG_ERR_LOAD_SESSION_NOENT;
dcf266c0
JG
2696 }
2697 return ret;
2698}
2699
60f70355
JG
2700/* Allocate dirent as recommended by READDIR(3), NOTES on readdir_r */
2701static
2702struct dirent *alloc_dirent(const char *path)
2703{
2704 size_t len;
2705 long name_max;
2706 struct dirent *entry;
2707
2708 name_max = pathconf(path, _PC_NAME_MAX);
2709 if (name_max == -1) {
2710 name_max = PATH_MAX;
2711 }
2712 len = offsetof(struct dirent, d_name) + name_max + 1;
2713 entry = zmalloc(len);
2714 return entry;
2715}
2716
dcf266c0
JG
2717static
2718int load_session_from_path(const char *path, const char *session_name,
2719 struct session_config_validation_ctx *validation_ctx, int override)
2720{
2721 int ret, session_found = !session_name;
dcf266c0
JG
2722 DIR *directory = NULL;
2723
2724 assert(path);
2725 assert(validation_ctx);
2726
4af16958
DG
2727 directory = opendir(path);
2728 if (!directory) {
11143783
DG
2729 switch (errno) {
2730 case ENOTDIR:
0f0a81b5
DG
2731 /* Try the file loading. */
2732 break;
11143783
DG
2733 case ENOENT:
2734 ret = -LTTNG_ERR_LOAD_SESSION_NOENT;
2735 goto end;
2736 default:
0f0a81b5
DG
2737 ret = -LTTNG_ERR_LOAD_IO_FAIL;
2738 goto end;
4af16958 2739 }
dcf266c0 2740 }
4af16958 2741 if (directory) {
dcf266c0
JG
2742 struct dirent *entry;
2743 struct dirent *result;
2744 char *file_path = NULL;
2745 size_t path_len = strlen(path);
2746
2747 if (path_len >= PATH_MAX) {
2748 ret = -LTTNG_ERR_INVALID;
2749 goto end;
2750 }
2751
60f70355 2752 entry = alloc_dirent(path);
dcf266c0
JG
2753 if (!entry) {
2754 ret = -LTTNG_ERR_NOMEM;
2755 goto end;
2756 }
2757
dcf266c0
JG
2758 file_path = zmalloc(PATH_MAX);
2759 if (!file_path) {
2760 ret = -LTTNG_ERR_NOMEM;
2761 free(entry);
2762 goto end;
2763 }
2764
2765 strncpy(file_path, path, path_len);
2766 if (file_path[path_len - 1] != '/') {
2767 file_path[path_len++] = '/';
2768 }
2769
4af16958 2770 ret = 0;
dcf266c0
JG
2771 /* Search for *.lttng files */
2772 while (!readdir_r(directory, entry, &result) && result) {
2773 size_t file_name_len = strlen(result->d_name);
2774
2775 if (file_name_len <=
2776 sizeof(DEFAULT_SESSION_CONFIG_FILE_EXTENSION)) {
2777 continue;
2778 }
2779
431f702e 2780 if (path_len + file_name_len >= PATH_MAX) {
dcf266c0
JG
2781 continue;
2782 }
2783
2784 if (strcmp(DEFAULT_SESSION_CONFIG_FILE_EXTENSION,
2785 result->d_name + file_name_len - sizeof(
2786 DEFAULT_SESSION_CONFIG_FILE_EXTENSION) + 1)) {
2787 continue;
2788 }
2789
2790 strncpy(file_path + path_len, result->d_name, file_name_len);
2791 file_path[path_len + file_name_len] = '\0';
2792
2793 ret = load_session_from_file(file_path, session_name,
2794 validation_ctx, override);
2795 if (session_name && !ret) {
2796 session_found = 1;
2797 break;
2798 }
2799 }
2800
2801 free(entry);
2802 free(file_path);
2803 } else {
2804 ret = load_session_from_file(path, session_name,
2805 validation_ctx, override);
2806 if (ret) {
2807 goto end;
2808 } else {
2809 session_found = 1;
2810 }
2811 }
2812
2813end:
2814 if (directory) {
2815 if (closedir(directory)) {
2816 PERROR("closedir");
2817 }
2818 }
2819
2820 if (!session_found) {
a96bc65d 2821 ret = -LTTNG_ERR_LOAD_SESSION_NOENT;
dcf266c0
JG
2822 }
2823
2824 return ret;
2825}
2826
ab38c13f
DG
2827/*
2828 * Validate that the given path's credentials and the current process have the
cf53c06d 2829 * same UID. If so, return 1 else return 0 if it does NOT match.
ab38c13f
DG
2830 */
2831static int validate_path_creds(const char *path)
2832{
2833 int ret, uid = getuid();
2834 struct stat buf;
2835
2836 assert(path);
2837
cf53c06d 2838 if (uid == 0) {
ab38c13f
DG
2839 goto valid;
2840 }
2841
2842 ret = stat(path, &buf);
2843 if (ret < 0) {
2844 if (errno != ENOENT) {
2845 PERROR("stat");
2846 }
2847 ret = -LTTNG_ERR_INVALID;
2848 goto valid;
2849 }
2850
2851 if (buf.st_uid != uid) {
2852 goto invalid;
2853 }
2854
2855valid:
ab38c13f 2856 return 1;
cf53c06d
DG
2857invalid:
2858 return 0;
ab38c13f
DG
2859}
2860
dcf266c0
JG
2861LTTNG_HIDDEN
2862int config_load_session(const char *path, const char *session_name,
ab38c13f 2863 int override, unsigned int autoload)
dcf266c0
JG
2864{
2865 int ret;
cf53c06d 2866 const char *path_ptr = NULL;
dcf266c0
JG
2867 struct session_config_validation_ctx validation_ctx = { 0 };
2868
2869 ret = init_session_config_validation_ctx(&validation_ctx);
2870 if (ret) {
2871 goto end;
2872 }
2873
2874 if (!path) {
ab38c13f
DG
2875 char *home_path;
2876 const char *sys_path;
2877
dcf266c0 2878 /* Try home path */
ab38c13f 2879 home_path = utils_get_home_dir();
dcf266c0 2880 if (home_path) {
ab38c13f 2881 char path[PATH_MAX];
dcf266c0 2882
d4fcf703
DG
2883 /*
2884 * Try user session configuration path. Ignore error here so we can
2885 * continue loading the system wide sessions.
2886 */
ab38c13f
DG
2887 if (autoload) {
2888 ret = snprintf(path, sizeof(path),
2889 DEFAULT_SESSION_HOME_CONFIGPATH "/"
2890 DEFAULT_SESSION_CONFIG_AUTOLOAD, home_path);
cf53c06d
DG
2891 if (ret < 0) {
2892 PERROR("snprintf session autoload home config path");
2893 goto end;
2894 }
2895
2896 /*
2897 * Credentials are only validated for the autoload in order to
2898 * avoid any user session daemon to try to load kernel sessions
2899 * automatically and failing all the times.
2900 */
2901 ret = validate_path_creds(path);
2902 if (ret) {
2903 path_ptr = path;
2904 }
ab38c13f
DG
2905 } else {
2906 ret = snprintf(path, sizeof(path),
2907 DEFAULT_SESSION_HOME_CONFIGPATH, home_path);
cf53c06d
DG
2908 if (ret < 0) {
2909 PERROR("snprintf session home config path");
2910 goto end;
2911 }
2912 path_ptr = path;
ab38c13f 2913 }
cf53c06d
DG
2914 if (path_ptr) {
2915 ret = load_session_from_path(path_ptr, session_name,
d4fcf703
DG
2916 &validation_ctx, override);
2917 if (ret && ret != -LTTNG_ERR_LOAD_SESSION_NOENT) {
2918 goto end;
2919 }
2920 /*
2921 * Continue even if the session was found since we have to try
2922 * the system wide sessions.
2923 */
ab38c13f 2924 }
d4fcf703 2925 }
ab38c13f 2926
cf53c06d
DG
2927 /* Reset path pointer for the system wide dir. */
2928 path_ptr = NULL;
2929
d4fcf703
DG
2930 /* Try system wide configuration directory. */
2931 if (autoload) {
2932 sys_path = DEFAULT_SESSION_SYSTEM_CONFIGPATH "/"
2933 DEFAULT_SESSION_CONFIG_AUTOLOAD;
cf53c06d
DG
2934 ret = validate_path_creds(sys_path);
2935 if (ret) {
2936 path_ptr = sys_path;
2937 }
d4fcf703 2938 } else {
cf53c06d
DG
2939 sys_path = DEFAULT_SESSION_SYSTEM_CONFIGPATH;
2940 path_ptr = sys_path;
d4fcf703
DG
2941 }
2942
cf53c06d
DG
2943 if (path_ptr) {
2944 ret = load_session_from_path(path_ptr, session_name,
d4fcf703 2945 &validation_ctx, override);
dcf266c0
JG
2946 }
2947 } else {
2948 ret = access(path, F_OK);
2949 if (ret < 0) {
2950 PERROR("access");
2951 switch (errno) {
2952 case ENOENT:
2953 ret = -LTTNG_ERR_INVALID;
2954 WARN("Session configuration path does not exist.");
2955 break;
2956 case EACCES:
2957 ret = -LTTNG_ERR_EPERM;
2958 break;
2959 default:
2960 ret = -LTTNG_ERR_UNK;
2961 break;
2962 }
2963 goto end;
2964 }
2965
2966 ret = load_session_from_path(path, session_name,
2967 &validation_ctx, override);
2968 }
2969end:
2970 fini_session_config_validation_ctx(&validation_ctx);
d2b6efff
JG
2971 if (ret == -LTTNG_ERR_LOAD_SESSION_NOENT && !session_name && !path) {
2972 /*
2973 * Don't report an error if no sessions are found when called
2974 * without a session_name or a search path.
2975 */
2976 ret = 0;
2977 }
dcf266c0
JG
2978 return ret;
2979}
This page took 0.153881 seconds and 4 git commands to generate.