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