clang-tidy: add Chrome-inspired checks
[lttng-tools.git] / src / common / config / session-config.cpp
CommitLineData
1501a7f3 1/*
ab5be9fa 2 * Copyright (C) 2013 Jérémie Galarneau <jeremie.galarneau@efficios.com>
1501a7f3 3 *
c922647d 4 * SPDX-License-Identifier: LGPL-2.1-only
1501a7f3 5 *
1501a7f3
JG
6 */
7
159b042f 8#include "lttng/tracker.h"
6c1c0768 9#define _LGPL_SOURCE
28ab034a
JG
10#include "config-internal.hpp"
11#include "session-config.hpp"
1501a7f3 12
28ab034a 13#include <common/compat/getenv.hpp>
c9e313bc 14#include <common/defaults.hpp>
28ab034a 15#include <common/dynamic-buffer.hpp>
c9e313bc
SM
16#include <common/error.hpp>
17#include <common/macros.hpp>
18#include <common/utils.hpp>
28ab034a 19
fb198a11 20#include <lttng/lttng-error.h>
dcf266c0 21#include <lttng/lttng.h>
259c2674 22#include <lttng/rotation.h>
28ab034a 23#include <lttng/snapshot.h>
c1e83fb4 24#include <lttng/userspace-probe.h>
1501a7f3 25
28ab034a
JG
26#include <ctype.h>
27#include <dirent.h>
28#include <inttypes.h>
29#include <libxml/parser.h>
30#include <libxml/tree.h>
31#include <libxml/valid.h>
32#include <libxml/xmlschemas.h>
33#include <stdbool.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <sys/stat.h>
38#include <sys/types.h>
39#include <unistd.h>
1501a7f3 40
c1e83fb4
FD
41#define CONFIG_USERSPACE_PROBE_LOOKUP_METHOD_NAME_MAX_LEN 7
42
f1494934 43namespace {
dcf266c0
JG
44struct session_config_validation_ctx {
45 xmlSchemaParserCtxtPtr parser_ctx;
46 xmlSchemaPtr schema;
47 xmlSchemaValidCtxtPtr schema_validation_ctx;
48};
f1494934 49} /* namespace */
dcf266c0 50
28ab034a 51const char *const config_element_all = "all";
3afa94ae 52LTTNG_EXPORT const char *config_xml_encoding = "UTF-8";
28ab034a
JG
53LTTNG_EXPORT size_t config_xml_encoding_bytes_per_char = 2; /* Size of the encoding's largest
54 character */
3afa94ae
SM
55LTTNG_EXPORT const char *config_xml_indent_string = "\t";
56LTTNG_EXPORT const char *config_xml_true = "true";
57LTTNG_EXPORT const char *config_xml_false = "false";
1501a7f3 58
28ab034a
JG
59const char *const config_element_channel = "channel";
60const char *const config_element_channels = "channels";
61const char *const config_element_domain = "domain";
62const char *const config_element_domains = "domains";
63const char *const config_element_event = "event";
64const char *const config_element_events = "events";
65const char *const config_element_context = "context";
66const char *const config_element_contexts = "contexts";
67const char *const config_element_attributes = "attributes";
68const char *const config_element_exclusion = "exclusion";
69const char *const config_element_exclusions = "exclusions";
70const char *const config_element_function_attributes = "function_attributes";
71const char *const config_element_probe_attributes = "probe_attributes";
72const char *const config_element_symbol_name = "symbol_name";
73const char *const config_element_address = "address";
74const char *const config_element_offset = "offset";
75
76const char *const config_element_userspace_probe_lookup = "lookup_method";
77const char *const config_element_userspace_probe_lookup_function_default = "DEFAULT";
78const char *const config_element_userspace_probe_lookup_function_elf = "ELF";
79const char *const config_element_userspace_probe_lookup_tracepoint_sdt = "SDT";
80const char *const config_element_userspace_probe_location_binary_path = "binary_path";
81const char *const config_element_userspace_probe_function_attributes =
82 "userspace_probe_function_attributes";
83const char *const config_element_userspace_probe_function_location_function_name = "function_name";
84const char *const config_element_userspace_probe_tracepoint_attributes =
85 "userspace_probe_tracepoint_attributes";
86const char *const config_element_userspace_probe_tracepoint_location_provider_name =
87 "provider_name";
88const char *const config_element_userspace_probe_tracepoint_location_probe_name = "probe_name";
89
90const char *const config_element_name = "name";
91const char *const config_element_enabled = "enabled";
92const char *const config_element_overwrite_mode = "overwrite_mode";
93const char *const config_element_subbuf_size = "subbuffer_size";
94const char *const config_element_num_subbuf = "subbuffer_count";
95const char *const config_element_switch_timer_interval = "switch_timer_interval";
96const char *const config_element_read_timer_interval = "read_timer_interval";
97const char *const config_element_monitor_timer_interval = "monitor_timer_interval";
98const char *const config_element_blocking_timeout = "blocking_timeout";
99const char *const config_element_output = "output";
100const char *const config_element_output_type = "output_type";
101const char *const config_element_tracefile_size = "tracefile_size";
102const char *const config_element_tracefile_count = "tracefile_count";
103const char *const config_element_live_timer_interval = "live_timer_interval";
104const char *const config_element_discarded_events = "discarded_events";
105const char *const config_element_lost_packets = "lost_packets";
106const char *const config_element_type = "type";
107const char *const config_element_buffer_type = "buffer_type";
108const char *const config_element_session = "session";
109const char *const config_element_sessions = "sessions";
110const char *const config_element_context_perf = "perf";
111const char *const config_element_context_app = "app";
112const char *const config_element_context_app_provider_name = "provider_name";
113const char *const config_element_context_app_ctx_name = "ctx_name";
114const char *const config_element_config = "config";
115const char *const config_element_started = "started";
116const char *const config_element_snapshot_mode = "snapshot_mode";
117const char *const config_element_loglevel = "loglevel";
118const char *const config_element_loglevel_type = "loglevel_type";
119const char *const config_element_filter = "filter";
120const char *const config_element_filter_expression = "filter_expression";
121const char *const config_element_snapshot_outputs = "snapshot_outputs";
122const char *const config_element_consumer_output = "consumer_output";
123const char *const config_element_destination = "destination";
124const char *const config_element_path = "path";
125const char *const config_element_net_output = "net_output";
126const char *const config_element_control_uri = "control_uri";
127const char *const config_element_data_uri = "data_uri";
128const char *const config_element_max_size = "max_size";
129const char *const config_element_pid = "pid";
130const char *const config_element_pids = "pids";
131const char *const config_element_shared_memory_path = "shared_memory_path";
132
133const char *const config_element_process_attr_id = "id";
134const char *const config_element_process_attr_tracker_pid = "pid_process_attr_tracker";
135const char *const config_element_process_attr_tracker_vpid = "vpid_process_attr_tracker";
136const char *const config_element_process_attr_tracker_uid = "uid_process_attr_tracker";
137const char *const config_element_process_attr_tracker_vuid = "vuid_process_attr_tracker";
138const char *const config_element_process_attr_tracker_gid = "gid_process_attr_tracker";
139const char *const config_element_process_attr_tracker_vgid = "vgid_process_attr_tracker";
140const char *const config_element_process_attr_trackers = "process_attr_trackers";
141const char *const config_element_process_attr_values = "process_attr_values";
142const char *const config_element_process_attr_value_type = "process_attr_value_type";
143const char *const config_element_process_attr_pid_value = "pid";
144const char *const config_element_process_attr_vpid_value = "vpid";
145const char *const config_element_process_attr_uid_value = "uid";
146const char *const config_element_process_attr_vuid_value = "vuid";
147const char *const config_element_process_attr_gid_value = "gid";
148const char *const config_element_process_attr_vgid_value = "vgid";
149const char *const config_element_process_attr_tracker_type = "process_attr_tracker_type";
fb198a11 150
f7af9a72 151/* Used for support of legacy tracker serialization (< 2.12). */
28ab034a
JG
152const char *const config_element_trackers_legacy = "trackers";
153const char *const config_element_pid_tracker_legacy = "pid_tracker";
154const char *const config_element_tracker_targets_legacy = "targets";
155const char *const config_element_tracker_pid_legacy = "pid";
156
157const char *const config_element_rotation_schedules = "rotation_schedules";
158const char *const config_element_rotation_schedule_periodic = "periodic";
159const char *const config_element_rotation_schedule_periodic_time_us = "time_us";
160const char *const config_element_rotation_schedule_size_threshold = "size_threshold";
161const char *const config_element_rotation_schedule_size_threshold_bytes = "bytes";
162
163const char *const config_domain_type_kernel = "KERNEL";
164const char *const config_domain_type_ust = "UST";
165const char *const config_domain_type_jul = "JUL";
166const char *const config_domain_type_log4j = "LOG4J";
167const char *const config_domain_type_python = "PYTHON";
168
169const char *const config_buffer_type_per_pid = "PER_PID";
170const char *const config_buffer_type_per_uid = "PER_UID";
171const char *const config_buffer_type_global = "GLOBAL";
172
173const char *const config_overwrite_mode_discard = "DISCARD";
174const char *const config_overwrite_mode_overwrite = "OVERWRITE";
175
176const char *const config_output_type_splice = "SPLICE";
177const char *const config_output_type_mmap = "MMAP";
178
179const char *const config_loglevel_type_all = "ALL";
180const char *const config_loglevel_type_range = "RANGE";
181const char *const config_loglevel_type_single = "SINGLE";
182
183const char *const config_event_type_all = "ALL";
184const char *const config_event_type_tracepoint = "TRACEPOINT";
185const char *const config_event_type_probe = "PROBE";
186const char *const config_event_type_userspace_probe = "USERSPACE_PROBE";
187const char *const config_event_type_function = "FUNCTION";
188const char *const config_event_type_function_entry = "FUNCTION_ENTRY";
189const char *const config_event_type_noop = "NOOP";
190const char *const config_event_type_syscall = "SYSCALL";
191const char *const config_event_type_kprobe = "KPROBE";
192const char *const config_event_type_kretprobe = "KRETPROBE";
193
194const char *const config_event_context_pid = "PID";
195const char *const config_event_context_procname = "PROCNAME";
196const char *const config_event_context_prio = "PRIO";
197const char *const config_event_context_nice = "NICE";
198const char *const config_event_context_vpid = "VPID";
199const char *const config_event_context_tid = "TID";
200const char *const config_event_context_vtid = "VTID";
201const char *const config_event_context_ppid = "PPID";
202const char *const config_event_context_vppid = "VPPID";
203const char *const config_event_context_pthread_id = "PTHREAD_ID";
204const char *const config_event_context_hostname = "HOSTNAME";
205const char *const config_event_context_ip = "IP";
206const char *const config_event_context_perf_thread_counter = "PERF_THREAD_COUNTER";
207const char *const config_event_context_app = "APP";
208const char *const config_event_context_interruptible = "INTERRUPTIBLE";
209const char *const config_event_context_preemptible = "PREEMPTIBLE";
210const char *const config_event_context_need_reschedule = "NEED_RESCHEDULE";
211const char *const config_event_context_migratable = "MIGRATABLE";
212const char *const config_event_context_callstack_user = "CALLSTACK_USER";
213const char *const config_event_context_callstack_kernel = "CALLSTACK_KERNEL";
214const char *const config_event_context_cgroup_ns = "CGROUP_NS";
215const char *const config_event_context_ipc_ns = "IPC_NS";
216const char *const config_event_context_mnt_ns = "MNT_NS";
217const char *const config_event_context_net_ns = "NET_NS";
218const char *const config_event_context_pid_ns = "PID_NS";
219const char *const config_event_context_time_ns = "TIME_NS";
220const char *const config_event_context_user_ns = "USER_NS";
221const char *const config_event_context_uts_ns = "UTS_NS";
222const char *const config_event_context_uid = "UID";
223const char *const config_event_context_euid = "EUID";
224const char *const config_event_context_suid = "SUID";
225const char *const config_event_context_gid = "GID";
226const char *const config_event_context_egid = "EGID";
227const char *const config_event_context_sgid = "SGID";
228const char *const config_event_context_vuid = "VUID";
229const char *const config_event_context_veuid = "VEUID";
230const char *const config_event_context_vsuid = "VSUID";
231const char *const config_event_context_vgid = "VGID";
232const char *const config_event_context_vegid = "VEGID";
233const char *const config_event_context_vsgid = "VSGID";
fb198a11 234
fbd987c9 235/* Deprecated symbols */
3afa94ae 236LTTNG_EXPORT const char *config_element_perf;
fbd987c9 237
d7b645e2
JR
238enum process_event_node_phase {
239 CREATION = 0,
240 ENABLE = 1,
241};
242
f1494934 243namespace {
dcf266c0
JG
244struct consumer_output {
245 int enabled;
246 char *path;
247 char *control_uri;
248 char *data_uri;
249};
f1494934 250} /* namespace */
dcf266c0 251
36f2332b
JG
252/*
253 * Returns a xmlChar string which must be released using xmlFree().
254 */
255static xmlChar *encode_string(const char *in_str)
256{
cd9adb8b 257 xmlChar *out_str = nullptr;
36f2332b
JG
258 xmlCharEncodingHandlerPtr handler;
259 int out_len, ret, in_len;
260
a0377dfe 261 LTTNG_ASSERT(in_str);
36f2332b
JG
262
263 handler = xmlFindCharEncodingHandler(config_xml_encoding);
264 if (!handler) {
265 ERR("xmlFindCharEncodingHandler return NULL!. Configure issue!");
266 goto end;
267 }
268
269 in_len = strlen(in_str);
270 /*
f76d886f
JG
271 * Add 1 byte for the NULL terminted character. The factor 4 here is
272 * used because UTF-8 characters can take up to 4 bytes.
36f2332b 273 */
f76d886f 274 out_len = (in_len * 4) + 1;
3afa94ae 275 out_str = (xmlChar *) xmlMalloc(out_len);
36f2332b
JG
276 if (!out_str) {
277 goto end;
278 }
279
280 ret = handler->input(out_str, &out_len, (const xmlChar *) in_str, &in_len);
281 if (ret < 0) {
282 xmlFree(out_str);
cd9adb8b 283 out_str = nullptr;
36f2332b
JG
284 goto end;
285 }
286
287 /* out_len is now the size of out_str */
288 out_str[out_len] = '\0';
289end:
290 return out_str;
291}
292
705bb62f 293struct config_writer *config_writer_create(int fd_output, int indent)
36f2332b
JG
294{
295 int ret;
296 struct config_writer *writer;
297 xmlOutputBufferPtr buffer;
298
64803277 299 writer = zmalloc<config_writer>();
36f2332b
JG
300 if (!writer) {
301 PERROR("zmalloc config_writer_create");
302 goto end;
303 }
304
cd9adb8b 305 buffer = xmlOutputBufferCreateFd(fd_output, nullptr);
36f2332b
JG
306 if (!buffer) {
307 goto error_destroy;
308 }
309
310 writer->writer = xmlNewTextWriter(buffer);
cd9adb8b 311 ret = xmlTextWriterStartDocument(writer->writer, nullptr, config_xml_encoding, nullptr);
36f2332b
JG
312 if (ret < 0) {
313 goto error_destroy;
314 }
315
28ab034a 316 ret = xmlTextWriterSetIndentString(writer->writer, BAD_CAST config_xml_indent_string);
705bb62f 317 if (ret) {
36f2332b
JG
318 goto error_destroy;
319 }
320
705bb62f
JRJ
321 ret = xmlTextWriterSetIndent(writer->writer, indent);
322 if (ret) {
36f2332b
JG
323 goto error_destroy;
324 }
325
326end:
327 return writer;
328error_destroy:
329 config_writer_destroy(writer);
cd9adb8b 330 return nullptr;
36f2332b
JG
331}
332
36f2332b
JG
333int config_writer_destroy(struct config_writer *writer)
334{
335 int ret = 0;
336
337 if (!writer) {
338 ret = -EINVAL;
339 goto end;
340 }
341
342 if (xmlTextWriterEndDocument(writer->writer) < 0) {
343 WARN("Could not close XML document");
344 ret = -EIO;
345 }
346
347 if (writer->writer) {
348 xmlFreeTextWriter(writer->writer);
349 }
350
351 free(writer);
352end:
353 return ret;
354}
355
28ab034a 356int config_writer_open_element(struct config_writer *writer, const char *element_name)
36f2332b
JG
357{
358 int ret;
359 xmlChar *encoded_element_name;
360
361 if (!writer || !writer->writer || !element_name || !element_name[0]) {
362 ret = -1;
363 goto end;
364 }
365
366 encoded_element_name = encode_string(element_name);
367 if (!encoded_element_name) {
368 ret = -1;
369 goto end;
370 }
371
372 ret = xmlTextWriterStartElement(writer->writer, encoded_element_name);
373 xmlFree(encoded_element_name);
374end:
28676a1d 375 return ret >= 0 ? 0 : ret;
36f2332b
JG
376}
377
28ab034a 378int config_writer_write_attribute(struct config_writer *writer, const char *name, const char *value)
e10b6a1c
JG
379{
380 int ret;
cd9adb8b
JG
381 xmlChar *encoded_name = nullptr;
382 xmlChar *encoded_value = nullptr;
e10b6a1c
JG
383
384 if (!writer || !writer->writer || !name || !name[0]) {
385 ret = -1;
386 goto end;
387 }
388
389 encoded_name = encode_string(name);
390 if (!encoded_name) {
391 ret = -1;
392 goto end;
393 }
394
395 encoded_value = encode_string(value);
396 if (!encoded_value) {
397 ret = -1;
398 goto end;
399 }
400
28ab034a 401 ret = xmlTextWriterWriteAttribute(writer->writer, encoded_name, encoded_value);
e10b6a1c
JG
402end:
403 xmlFree(encoded_name);
404 xmlFree(encoded_value);
405 return ret >= 0 ? 0 : ret;
406}
407
36f2332b
JG
408int config_writer_close_element(struct config_writer *writer)
409{
410 int ret;
411
412 if (!writer || !writer->writer) {
413 ret = -1;
414 goto end;
415 }
416
417 ret = xmlTextWriterEndElement(writer->writer);
418end:
28676a1d 419 return ret >= 0 ? 0 : ret;
36f2332b
JG
420}
421
36f2332b 422int config_writer_write_element_unsigned_int(struct config_writer *writer,
28ab034a
JG
423 const char *element_name,
424 uint64_t value)
36f2332b
JG
425{
426 int ret;
427 xmlChar *encoded_element_name;
428
429 if (!writer || !writer->writer || !element_name || !element_name[0]) {
430 ret = -1;
431 goto end;
432 }
433
434 encoded_element_name = encode_string(element_name);
435 if (!encoded_element_name) {
436 ret = -1;
437 goto end;
438 }
439
28ab034a
JG
440 ret = xmlTextWriterWriteFormatElement(
441 writer->writer, encoded_element_name, "%" PRIu64, value);
36f2332b
JG
442 xmlFree(encoded_element_name);
443end:
28676a1d 444 return ret >= 0 ? 0 : ret;
36f2332b
JG
445}
446
36f2332b 447int config_writer_write_element_signed_int(struct config_writer *writer,
28ab034a
JG
448 const char *element_name,
449 int64_t value)
36f2332b
JG
450{
451 int ret;
452 xmlChar *encoded_element_name;
453
454 if (!writer || !writer->writer || !element_name || !element_name[0]) {
455 ret = -1;
456 goto end;
457 }
458
459 encoded_element_name = encode_string(element_name);
460 if (!encoded_element_name) {
461 ret = -1;
462 goto end;
463 }
464
28ab034a
JG
465 ret = xmlTextWriterWriteFormatElement(
466 writer->writer, encoded_element_name, "%" PRIi64, value);
36f2332b
JG
467 xmlFree(encoded_element_name);
468end:
28676a1d 469 return ret >= 0 ? 0 : ret;
36f2332b
JG
470}
471
36f2332b 472int config_writer_write_element_bool(struct config_writer *writer,
28ab034a
JG
473 const char *element_name,
474 int value)
36f2332b 475{
28ab034a
JG
476 return config_writer_write_element_string(
477 writer, element_name, value ? config_xml_true : config_xml_false);
36f2332b
JG
478}
479
2b166400 480int config_writer_write_element_double(struct config_writer *writer,
28ab034a
JG
481 const char *element_name,
482 double value)
2b166400
JR
483{
484 int ret;
485 xmlChar *encoded_element_name;
486
487 if (!writer || !writer->writer || !element_name || !element_name[0]) {
488 ret = -1;
489 goto end;
490 }
491
492 encoded_element_name = encode_string(element_name);
493 if (!encoded_element_name) {
494 ret = -1;
495 goto end;
496 }
497
28ab034a 498 ret = xmlTextWriterWriteFormatElement(writer->writer, encoded_element_name, "%f", value);
2b166400
JR
499 xmlFree(encoded_element_name);
500end:
501 return ret >= 0 ? 0 : ret;
502}
503
36f2332b 504int config_writer_write_element_string(struct config_writer *writer,
28ab034a
JG
505 const char *element_name,
506 const char *value)
36f2332b
JG
507{
508 int ret;
cd9adb8b
JG
509 xmlChar *encoded_element_name = nullptr;
510 xmlChar *encoded_value = nullptr;
36f2332b 511
28ab034a 512 if (!writer || !writer->writer || !element_name || !element_name[0] || !value) {
36f2332b
JG
513 ret = -1;
514 goto end;
515 }
516
517 encoded_element_name = encode_string(element_name);
518 if (!encoded_element_name) {
519 ret = -1;
520 goto end;
521 }
522
523 encoded_value = encode_string(value);
524 if (!encoded_value) {
525 ret = -1;
526 goto end;
527 }
528
28ab034a 529 ret = xmlTextWriterWriteElement(writer->writer, encoded_element_name, encoded_value);
36f2332b
JG
530end:
531 xmlFree(encoded_element_name);
532 xmlFree(encoded_value);
28676a1d 533 return ret >= 0 ? 0 : ret;
36f2332b 534}
dcf266c0 535
28ab034a
JG
536static ATTR_FORMAT_PRINTF(2, 3) void xml_error_handler(void *ctx __attribute__((unused)),
537 const char *format,
538 ...)
dcf266c0
JG
539{
540 char *errMsg;
541 va_list args;
542 int ret;
543
544 va_start(args, format);
545 ret = vasprintf(&errMsg, format, args);
6c043b48 546 va_end(args);
dcf266c0
JG
547 if (ret == -1) {
548 ERR("String allocation failed in xml error handler");
549 return;
550 }
dcf266c0
JG
551
552 fprintf(stderr, "XML Error: %s", errMsg);
553 free(errMsg);
554}
555
28ab034a 556static void fini_session_config_validation_ctx(struct session_config_validation_ctx *ctx)
dcf266c0
JG
557{
558 if (ctx->parser_ctx) {
559 xmlSchemaFreeParserCtxt(ctx->parser_ctx);
560 }
561
562 if (ctx->schema) {
563 xmlSchemaFree(ctx->schema);
564 }
565
566 if (ctx->schema_validation_ctx) {
567 xmlSchemaFreeValidCtxt(ctx->schema_validation_ctx);
568 }
569
570 memset(ctx, 0, sizeof(struct session_config_validation_ctx));
571}
572
cd9adb8b 573static char *get_session_config_xsd_path()
54e399cb
JG
574{
575 char *xsd_path;
e8fa9fb0 576 const char *base_path = lttng_secure_getenv(DEFAULT_SESSION_CONFIG_XSD_PATH_ENV);
54e399cb
JG
577 size_t base_path_len;
578 size_t max_path_len;
579
580 if (!base_path) {
581 base_path = DEFAULT_SESSION_CONFIG_XSD_PATH;
582 }
583
584 base_path_len = strlen(base_path);
28ab034a 585 max_path_len = base_path_len + sizeof(DEFAULT_SESSION_CONFIG_XSD_FILENAME) + 1;
64803277 586 xsd_path = zmalloc<char>(max_path_len);
54e399cb
JG
587 if (!xsd_path) {
588 goto end;
589 }
590
00a7f6f8 591 strcpy(xsd_path, base_path);
54e399cb
JG
592 if (xsd_path[base_path_len - 1] != '/') {
593 xsd_path[base_path_len++] = '/';
594 }
595
00a7f6f8 596 strcpy(xsd_path + base_path_len, DEFAULT_SESSION_CONFIG_XSD_FILENAME);
54e399cb
JG
597end:
598 return xsd_path;
599}
600
28ab034a 601static int init_session_config_validation_ctx(struct session_config_validation_ctx *ctx)
dcf266c0
JG
602{
603 int ret;
54e399cb
JG
604 char *xsd_path = get_session_config_xsd_path();
605
606 if (!xsd_path) {
607 ret = -LTTNG_ERR_NOMEM;
608 goto end;
609 }
dcf266c0 610
54e399cb 611 ctx->parser_ctx = xmlSchemaNewParserCtxt(xsd_path);
dcf266c0
JG
612 if (!ctx->parser_ctx) {
613 ERR("XSD parser context creation failed");
614 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
615 goto end;
616 }
cd9adb8b 617 xmlSchemaSetParserErrors(ctx->parser_ctx, xml_error_handler, xml_error_handler, nullptr);
dcf266c0
JG
618
619 ctx->schema = xmlSchemaParse(ctx->parser_ctx);
620 if (!ctx->schema) {
621 ERR("XSD parsing failed");
622 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
623 goto end;
624 }
625
626 ctx->schema_validation_ctx = xmlSchemaNewValidCtxt(ctx->schema);
627 if (!ctx->schema_validation_ctx) {
628 ERR("XSD validation context creation failed");
629 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
630 goto end;
631 }
632
28ab034a 633 xmlSchemaSetValidErrors(
cd9adb8b 634 ctx->schema_validation_ctx, xml_error_handler, xml_error_handler, nullptr);
dcf266c0
JG
635 ret = 0;
636
637end:
638 if (ret) {
639 fini_session_config_validation_ctx(ctx);
640 }
641
54e399cb 642 free(xsd_path);
dcf266c0
JG
643 return ret;
644}
645
28ab034a 646static int parse_uint(xmlChar *str, uint64_t *val)
dcf266c0
JG
647{
648 int ret;
649 char *endptr;
650
651 if (!str || !val) {
652 ret = -1;
653 goto end;
654 }
655
656 *val = strtoull((const char *) str, &endptr, 10);
657 if (!endptr || *endptr) {
658 ret = -1;
659 } else {
660 ret = 0;
661 }
662
663end:
664 return ret;
665}
666
28ab034a 667static int parse_int(xmlChar *str, int64_t *val)
dcf266c0
JG
668{
669 int ret;
670 char *endptr;
671
672 if (!str || !val) {
673 ret = -1;
674 goto end;
675 }
676
677 *val = strtoll((const char *) str, &endptr, 10);
678 if (!endptr || *endptr) {
679 ret = -1;
680 } else {
681 ret = 0;
682 }
683
684end:
685 return ret;
686}
687
28ab034a 688static int parse_bool(xmlChar *str, int *val)
dcf266c0
JG
689{
690 int ret = 0;
691
692 if (!str || !val) {
693 ret = -1;
694 goto end;
695 }
696
28ab034a 697 if (!strcmp((const char *) str, config_xml_true) || !strcmp((const char *) str, "1")) {
dcf266c0 698 *val = 1;
47945b17 699 } else if (!strcmp((const char *) str, config_xml_false) ||
28ab034a 700 !strcmp((const char *) str, "0")) {
dcf266c0
JG
701 *val = 0;
702 } else {
28ab034a 703 WARN("Invalid boolean value encountered (%s).", (const char *) str);
dcf266c0
JG
704 ret = -1;
705 }
706end:
707 return ret;
708}
709
28ab034a 710static int get_domain_type(xmlChar *domain)
dcf266c0
JG
711{
712 int ret;
713
714 if (!domain) {
715 goto error;
716 }
717
718 if (!strcmp((char *) domain, config_domain_type_kernel)) {
719 ret = LTTNG_DOMAIN_KERNEL;
720 } else if (!strcmp((char *) domain, config_domain_type_ust)) {
721 ret = LTTNG_DOMAIN_UST;
722 } else if (!strcmp((char *) domain, config_domain_type_jul)) {
723 ret = LTTNG_DOMAIN_JUL;
5cdb6027
DG
724 } else if (!strcmp((char *) domain, config_domain_type_log4j)) {
725 ret = LTTNG_DOMAIN_LOG4J;
0e115563
DG
726 } else if (!strcmp((char *) domain, config_domain_type_python)) {
727 ret = LTTNG_DOMAIN_PYTHON;
dcf266c0
JG
728 } else {
729 goto error;
730 }
731
732 return ret;
733error:
734 return -1;
735}
736
28ab034a 737static int get_buffer_type(xmlChar *buffer_type)
dcf266c0
JG
738{
739 int ret;
740
741 if (!buffer_type) {
742 goto error;
743 }
744
745 if (!strcmp((char *) buffer_type, config_buffer_type_global)) {
746 ret = LTTNG_BUFFER_GLOBAL;
747 } else if (!strcmp((char *) buffer_type, config_buffer_type_per_uid)) {
748 ret = LTTNG_BUFFER_PER_UID;
749 } else if (!strcmp((char *) buffer_type, config_buffer_type_per_pid)) {
750 ret = LTTNG_BUFFER_PER_PID;
751 } else {
752 goto error;
753 }
754
755 return ret;
756error:
757 return -1;
758}
759
28ab034a 760static int get_overwrite_mode(xmlChar *overwrite_mode)
dcf266c0
JG
761{
762 int ret;
763
764 if (!overwrite_mode) {
765 goto error;
766 }
767
768 if (!strcmp((char *) overwrite_mode, config_overwrite_mode_overwrite)) {
769 ret = 1;
28ab034a 770 } else if (!strcmp((char *) overwrite_mode, config_overwrite_mode_discard)) {
dcf266c0
JG
771 ret = 0;
772 } else {
773 goto error;
774 }
775
776 return ret;
777error:
778 return -1;
779}
780
28ab034a 781static int get_output_type(xmlChar *output_type)
dcf266c0
JG
782{
783 int ret;
784
785 if (!output_type) {
786 goto error;
787 }
788
789 if (!strcmp((char *) output_type, config_output_type_mmap)) {
790 ret = LTTNG_EVENT_MMAP;
791 } else if (!strcmp((char *) output_type, config_output_type_splice)) {
792 ret = LTTNG_EVENT_SPLICE;
793 } else {
794 goto error;
795 }
796
797 return ret;
798error:
799 return -1;
800}
801
28ab034a 802static int get_event_type(xmlChar *event_type)
dcf266c0
JG
803{
804 int ret;
805
806 if (!event_type) {
807 goto error;
808 }
809
810 if (!strcmp((char *) event_type, config_event_type_all)) {
811 ret = LTTNG_EVENT_ALL;
812 } else if (!strcmp((char *) event_type, config_event_type_tracepoint)) {
813 ret = LTTNG_EVENT_TRACEPOINT;
814 } else if (!strcmp((char *) event_type, config_event_type_probe)) {
815 ret = LTTNG_EVENT_PROBE;
28ab034a 816 } else if (!strcmp((char *) event_type, config_event_type_userspace_probe)) {
c1e83fb4 817 ret = LTTNG_EVENT_USERSPACE_PROBE;
dcf266c0
JG
818 } else if (!strcmp((char *) event_type, config_event_type_function)) {
819 ret = LTTNG_EVENT_FUNCTION;
28ab034a 820 } else if (!strcmp((char *) event_type, config_event_type_function_entry)) {
dcf266c0
JG
821 ret = LTTNG_EVENT_FUNCTION_ENTRY;
822 } else if (!strcmp((char *) event_type, config_event_type_noop)) {
823 ret = LTTNG_EVENT_NOOP;
824 } else if (!strcmp((char *) event_type, config_event_type_syscall)) {
825 ret = LTTNG_EVENT_SYSCALL;
826 } else {
827 goto error;
828 }
829
830 return ret;
831error:
832 return -1;
833}
834
28ab034a 835static int get_loglevel_type(xmlChar *loglevel_type)
dcf266c0
JG
836{
837 int ret;
838
839 if (!loglevel_type) {
840 goto error;
841 }
842
843 if (!strcmp((char *) loglevel_type, config_loglevel_type_all)) {
844 ret = LTTNG_EVENT_LOGLEVEL_ALL;
28ab034a 845 } else if (!strcmp((char *) loglevel_type, config_loglevel_type_range)) {
dcf266c0 846 ret = LTTNG_EVENT_LOGLEVEL_RANGE;
28ab034a 847 } else if (!strcmp((char *) loglevel_type, config_loglevel_type_single)) {
dcf266c0
JG
848 ret = LTTNG_EVENT_LOGLEVEL_SINGLE;
849 } else {
850 goto error;
851 }
852
853 return ret;
854error:
855 return -1;
856}
857
858/*
859 * Return the context type or -1 on error.
860 */
28ab034a 861static int get_context_type(xmlChar *context_type)
dcf266c0
JG
862{
863 int ret;
864
865 if (!context_type) {
866 goto error;
867 }
868
869 if (!strcmp((char *) context_type, config_event_context_pid)) {
870 ret = LTTNG_EVENT_CONTEXT_PID;
28ab034a 871 } else if (!strcmp((char *) context_type, config_event_context_procname)) {
dcf266c0 872 ret = LTTNG_EVENT_CONTEXT_PROCNAME;
28ab034a 873 } else if (!strcmp((char *) context_type, config_event_context_prio)) {
dcf266c0 874 ret = LTTNG_EVENT_CONTEXT_PRIO;
28ab034a 875 } else if (!strcmp((char *) context_type, config_event_context_nice)) {
dcf266c0 876 ret = LTTNG_EVENT_CONTEXT_NICE;
28ab034a 877 } else if (!strcmp((char *) context_type, config_event_context_vpid)) {
dcf266c0 878 ret = LTTNG_EVENT_CONTEXT_VPID;
28ab034a 879 } else if (!strcmp((char *) context_type, config_event_context_tid)) {
dcf266c0 880 ret = LTTNG_EVENT_CONTEXT_TID;
28ab034a 881 } else if (!strcmp((char *) context_type, config_event_context_vtid)) {
dcf266c0 882 ret = LTTNG_EVENT_CONTEXT_VTID;
28ab034a 883 } else if (!strcmp((char *) context_type, config_event_context_ppid)) {
dcf266c0 884 ret = LTTNG_EVENT_CONTEXT_PPID;
28ab034a 885 } else if (!strcmp((char *) context_type, config_event_context_vppid)) {
dcf266c0 886 ret = LTTNG_EVENT_CONTEXT_VPPID;
28ab034a 887 } else if (!strcmp((char *) context_type, config_event_context_pthread_id)) {
dcf266c0 888 ret = LTTNG_EVENT_CONTEXT_PTHREAD_ID;
28ab034a 889 } else if (!strcmp((char *) context_type, config_event_context_hostname)) {
dcf266c0 890 ret = LTTNG_EVENT_CONTEXT_HOSTNAME;
28ab034a 891 } else if (!strcmp((char *) context_type, config_event_context_ip)) {
dcf266c0 892 ret = LTTNG_EVENT_CONTEXT_IP;
28ab034a 893 } else if (!strcmp((char *) context_type, config_event_context_interruptible)) {
1ae5e83e 894 ret = LTTNG_EVENT_CONTEXT_INTERRUPTIBLE;
28ab034a 895 } else if (!strcmp((char *) context_type, config_event_context_preemptible)) {
1ae5e83e 896 ret = LTTNG_EVENT_CONTEXT_PREEMPTIBLE;
28ab034a 897 } else if (!strcmp((char *) context_type, config_event_context_need_reschedule)) {
1ae5e83e 898 ret = LTTNG_EVENT_CONTEXT_NEED_RESCHEDULE;
28ab034a 899 } else if (!strcmp((char *) context_type, config_event_context_migratable)) {
1ae5e83e 900 ret = LTTNG_EVENT_CONTEXT_MIGRATABLE;
28ab034a 901 } else if (!strcmp((char *) context_type, config_event_context_callstack_user)) {
16c4c991 902 ret = LTTNG_EVENT_CONTEXT_CALLSTACK_USER;
28ab034a 903 } else if (!strcmp((char *) context_type, config_event_context_callstack_kernel)) {
16c4c991 904 ret = LTTNG_EVENT_CONTEXT_CALLSTACK_KERNEL;
28ab034a 905 } else if (!strcmp((char *) context_type, config_event_context_cgroup_ns)) {
40e14884 906 ret = LTTNG_EVENT_CONTEXT_CGROUP_NS;
28ab034a 907 } else if (!strcmp((char *) context_type, config_event_context_ipc_ns)) {
40e14884 908 ret = LTTNG_EVENT_CONTEXT_IPC_NS;
28ab034a 909 } else if (!strcmp((char *) context_type, config_event_context_mnt_ns)) {
40e14884 910 ret = LTTNG_EVENT_CONTEXT_MNT_NS;
28ab034a 911 } else if (!strcmp((char *) context_type, config_event_context_net_ns)) {
40e14884 912 ret = LTTNG_EVENT_CONTEXT_NET_NS;
28ab034a 913 } else if (!strcmp((char *) context_type, config_event_context_pid_ns)) {
40e14884 914 ret = LTTNG_EVENT_CONTEXT_PID_NS;
28ab034a 915 } else if (!strcmp((char *) context_type, config_event_context_time_ns)) {
d37ac3cd 916 ret = LTTNG_EVENT_CONTEXT_TIME_NS;
28ab034a 917 } else if (!strcmp((char *) context_type, config_event_context_user_ns)) {
40e14884 918 ret = LTTNG_EVENT_CONTEXT_USER_NS;
28ab034a 919 } else if (!strcmp((char *) context_type, config_event_context_uts_ns)) {
40e14884 920 ret = LTTNG_EVENT_CONTEXT_UTS_NS;
28ab034a 921 } else if (!strcmp((char *) context_type, config_event_context_uid)) {
499cbfa1 922 ret = LTTNG_EVENT_CONTEXT_UID;
28ab034a 923 } else if (!strcmp((char *) context_type, config_event_context_euid)) {
499cbfa1 924 ret = LTTNG_EVENT_CONTEXT_EUID;
28ab034a 925 } else if (!strcmp((char *) context_type, config_event_context_suid)) {
499cbfa1 926 ret = LTTNG_EVENT_CONTEXT_SUID;
28ab034a 927 } else if (!strcmp((char *) context_type, config_event_context_gid)) {
499cbfa1 928 ret = LTTNG_EVENT_CONTEXT_GID;
28ab034a 929 } else if (!strcmp((char *) context_type, config_event_context_egid)) {
499cbfa1 930 ret = LTTNG_EVENT_CONTEXT_EGID;
28ab034a 931 } else if (!strcmp((char *) context_type, config_event_context_sgid)) {
499cbfa1 932 ret = LTTNG_EVENT_CONTEXT_SGID;
28ab034a 933 } else if (!strcmp((char *) context_type, config_event_context_vuid)) {
499cbfa1 934 ret = LTTNG_EVENT_CONTEXT_VUID;
28ab034a 935 } else if (!strcmp((char *) context_type, config_event_context_veuid)) {
499cbfa1 936 ret = LTTNG_EVENT_CONTEXT_VEUID;
28ab034a 937 } else if (!strcmp((char *) context_type, config_event_context_vsuid)) {
499cbfa1 938 ret = LTTNG_EVENT_CONTEXT_VSUID;
28ab034a 939 } else if (!strcmp((char *) context_type, config_event_context_vgid)) {
499cbfa1 940 ret = LTTNG_EVENT_CONTEXT_VGID;
28ab034a 941 } else if (!strcmp((char *) context_type, config_event_context_vegid)) {
499cbfa1 942 ret = LTTNG_EVENT_CONTEXT_VEGID;
28ab034a 943 } else if (!strcmp((char *) context_type, config_event_context_vsgid)) {
499cbfa1 944 ret = LTTNG_EVENT_CONTEXT_VSGID;
dcf266c0
JG
945 } else {
946 goto error;
947 }
948
949 return ret;
950error:
951 return -1;
952}
953
28ab034a 954static int init_domain(xmlNodePtr domain_node, struct lttng_domain *domain)
dcf266c0
JG
955{
956 int ret;
957 xmlNodePtr node;
958
28ab034a 959 for (node = xmlFirstElementChild(domain_node); node; node = xmlNextElementSibling(node)) {
dcf266c0
JG
960 if (!strcmp((const char *) node->name, config_element_type)) {
961 /* domain type */
962 xmlChar *node_content = xmlNodeGetContent(node);
963 if (!node_content) {
964 ret = -LTTNG_ERR_NOMEM;
965 goto end;
966 }
967
968 ret = get_domain_type(node_content);
969 free(node_content);
970 if (ret < 0) {
971 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
972 goto end;
973 }
974
3afa94ae 975 domain->type = (lttng_domain_type) ret;
28ab034a 976 } else if (!strcmp((const char *) node->name, config_element_buffer_type)) {
dcf266c0
JG
977 /* buffer type */
978 xmlChar *node_content = xmlNodeGetContent(node);
979 if (!node_content) {
980 ret = -LTTNG_ERR_NOMEM;
981 goto end;
982 }
983
984 ret = get_buffer_type(node_content);
985 free(node_content);
986 if (ret < 0) {
987 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
988 goto end;
989 }
990
3afa94ae 991 domain->buf_type = (lttng_buffer_type) ret;
dcf266c0
JG
992 }
993 }
994 ret = 0;
995end:
996 return ret;
997}
998
28ab034a 999static int get_net_output_uris(xmlNodePtr net_output_node, char **control_uri, char **data_uri)
dcf266c0
JG
1000{
1001 xmlNodePtr node;
1002
1003 for (node = xmlFirstElementChild(net_output_node); node;
28ab034a 1004 node = xmlNextElementSibling(node)) {
dcf266c0
JG
1005 if (!strcmp((const char *) node->name, config_element_control_uri)) {
1006 /* control_uri */
1007 *control_uri = (char *) xmlNodeGetContent(node);
1008 if (!*control_uri) {
1009 break;
1010 }
1011 } else {
1012 /* data_uri */
1013 *data_uri = (char *) xmlNodeGetContent(node);
1014 if (!*data_uri) {
1015 break;
1016 }
1017 }
1018 }
1019
1020 return *control_uri || *data_uri ? 0 : -LTTNG_ERR_LOAD_INVALID_CONFIG;
1021}
1022
28ab034a 1023static int process_consumer_output(xmlNodePtr consumer_output_node, struct consumer_output *output)
dcf266c0
JG
1024{
1025 int ret;
1026 xmlNodePtr node;
1027
a0377dfe 1028 LTTNG_ASSERT(output);
dcf266c0
JG
1029
1030 for (node = xmlFirstElementChild(consumer_output_node); node;
28ab034a 1031 node = xmlNextElementSibling(node)) {
dcf266c0
JG
1032 if (!strcmp((const char *) node->name, config_element_enabled)) {
1033 xmlChar *enabled_str = xmlNodeGetContent(node);
1034
1035 /* enabled */
1036 if (!enabled_str) {
1037 ret = -LTTNG_ERR_NOMEM;
1038 goto end;
1039 }
1040
1041 ret = parse_bool(enabled_str, &output->enabled);
1042 free(enabled_str);
1043 if (ret) {
1044 goto end;
1045 }
1046 } else {
1047 xmlNodePtr output_type_node;
1048
1049 /* destination */
1050 output_type_node = xmlFirstElementChild(node);
1051 if (!output_type_node) {
1052 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1053 goto end;
1054 }
1055
28ab034a 1056 if (!strcmp((const char *) output_type_node->name, config_element_path)) {
dcf266c0
JG
1057 /* path */
1058 output->path = (char *) xmlNodeGetContent(output_type_node);
1059 if (!output->path) {
1060 ret = -LTTNG_ERR_NOMEM;
1061 goto end;
1062 }
1063 } else {
1064 /* net_output */
28ab034a
JG
1065 ret = get_net_output_uris(
1066 output_type_node, &output->control_uri, &output->data_uri);
dcf266c0
JG
1067 if (ret) {
1068 goto end;
1069 }
1070 }
1071 }
1072 }
1073 ret = 0;
1074
1075end:
1076 if (ret) {
1077 free(output->path);
1078 free(output->control_uri);
1079 free(output->data_uri);
1080 memset(output, 0, sizeof(struct consumer_output));
1081 }
1082 return ret;
1083}
1084
28ab034a
JG
1085static int create_snapshot_session(const char *session_name,
1086 xmlNodePtr output_node,
1087 const struct config_load_session_override_attr *overrides)
dcf266c0
JG
1088{
1089 int ret;
fbc3f258 1090 enum lttng_error_code ret_code;
cd9adb8b 1091 xmlNodePtr node = nullptr;
dcf266c0
JG
1092 xmlNodePtr snapshot_output_list_node;
1093 xmlNodePtr snapshot_output_node;
fbc3f258 1094 struct lttng_session_descriptor *session_descriptor = nullptr;
dcf266c0 1095
a0377dfe 1096 LTTNG_ASSERT(session_name);
fbc3f258 1097 LTTNG_ASSERT(output_node);
dcf266c0 1098
fbc3f258
JR
1099 /*
1100 * Use a descriptor without output since consumer output size is not
1101 * exposed by the session descriptor api.
1102 */
1103 session_descriptor = lttng_session_descriptor_snapshot_create(session_name);
1104 if (session_descriptor == nullptr) {
1105 ret = -LTTNG_ERR_NOMEM;
dcf266c0
JG
1106 goto end;
1107 }
1108
fbc3f258
JR
1109 ret_code = lttng_create_session_ext(session_descriptor);
1110 if (ret_code != LTTNG_OK) {
1111 ret = -ret_code;
dcf266c0
JG
1112 goto end;
1113 }
1114
1115 snapshot_output_list_node = xmlFirstElementChild(output_node);
1116
1117 /* Parse and create snapshot outputs */
28ab034a
JG
1118 for (snapshot_output_node = xmlFirstElementChild(snapshot_output_list_node);
1119 snapshot_output_node;
1120 snapshot_output_node = xmlNextElementSibling(snapshot_output_node)) {
cd9adb8b 1121 char *name = nullptr;
dcf266c0 1122 uint64_t max_size = UINT64_MAX;
1c9a0b0e 1123 struct consumer_output output = {};
cd9adb8b
JG
1124 struct lttng_snapshot_output *snapshot_output = nullptr;
1125 const char *control_uri = nullptr;
1126 const char *data_uri = nullptr;
1127 const char *path = nullptr;
dcf266c0
JG
1128
1129 for (node = xmlFirstElementChild(snapshot_output_node); node;
28ab034a
JG
1130 node = xmlNextElementSibling(node)) {
1131 if (!strcmp((const char *) node->name, config_element_name)) {
dcf266c0
JG
1132 /* name */
1133 name = (char *) xmlNodeGetContent(node);
1134 if (!name) {
1135 ret = -LTTNG_ERR_NOMEM;
1136 goto error_snapshot_output;
1137 }
28ab034a 1138 } else if (!strcmp((const char *) node->name, config_element_max_size)) {
dcf266c0
JG
1139 xmlChar *content = xmlNodeGetContent(node);
1140
1141 /* max_size */
1142 if (!content) {
1143 ret = -LTTNG_ERR_NOMEM;
1144 goto error_snapshot_output;
1145 }
1146 ret = parse_uint(content, &max_size);
1147 free(content);
1148 if (ret) {
1149 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1150 goto error_snapshot_output;
1151 }
1152 } else {
1153 /* consumer_output */
1154 ret = process_consumer_output(node, &output);
1155 if (ret) {
1156 goto error_snapshot_output;
1157 }
1158 }
1159 }
1160
21a3f144
JR
1161 control_uri = output.control_uri;
1162 data_uri = output.data_uri;
1163 path = output.path;
1164
1b08cbce
JR
1165 if (overrides) {
1166 if (overrides->path_url) {
1b08cbce 1167 path = overrides->path_url;
21a3f144 1168 /* Control/data_uri are null */
cd9adb8b
JG
1169 control_uri = nullptr;
1170 data_uri = nullptr;
1b08cbce
JR
1171 } else {
1172 if (overrides->ctrl_url) {
1b08cbce 1173 control_uri = overrides->ctrl_url;
21a3f144 1174 /* path is null */
cd9adb8b 1175 path = nullptr;
1b08cbce
JR
1176 }
1177 if (overrides->data_url) {
1b08cbce 1178 data_uri = overrides->data_url;
21a3f144 1179 /* path is null */
cd9adb8b 1180 path = nullptr;
1b08cbce
JR
1181 }
1182 }
1b08cbce
JR
1183 }
1184
dcf266c0
JG
1185 snapshot_output = lttng_snapshot_output_create();
1186 if (!snapshot_output) {
1187 ret = -LTTNG_ERR_NOMEM;
1188 goto error_snapshot_output;
1189 }
1190
1191 ret = lttng_snapshot_output_set_name(name, snapshot_output);
1192 if (ret) {
1193 goto error_snapshot_output;
1194 }
1195
1196 ret = lttng_snapshot_output_set_size(max_size, snapshot_output);
1197 if (ret) {
1198 goto error_snapshot_output;
1199 }
1200
1b08cbce 1201 if (path) {
28ab034a 1202 ret = lttng_snapshot_output_set_ctrl_url(path, snapshot_output);
dcf266c0
JG
1203 if (ret) {
1204 goto error_snapshot_output;
1205 }
1206 } else {
1b08cbce
JR
1207 if (control_uri) {
1208 ret = lttng_snapshot_output_set_ctrl_url(control_uri,
28ab034a 1209 snapshot_output);
dcf266c0
JG
1210 if (ret) {
1211 goto error_snapshot_output;
1212 }
1213 }
1214
1b08cbce 1215 if (data_uri) {
28ab034a 1216 ret = lttng_snapshot_output_set_data_url(data_uri, snapshot_output);
dcf266c0
JG
1217 if (ret) {
1218 goto error_snapshot_output;
1219 }
1220 }
1221 }
1222
1223 ret = lttng_snapshot_add_output(session_name, snapshot_output);
28ab034a 1224 error_snapshot_output:
dcf266c0
JG
1225 free(name);
1226 free(output.path);
1227 free(output.control_uri);
1228 free(output.data_uri);
1229 lttng_snapshot_output_destroy(snapshot_output);
1230 if (ret) {
1231 goto end;
1232 }
1233 }
1234end:
fbc3f258 1235 lttng_session_descriptor_destroy(session_descriptor);
dcf266c0
JG
1236 return ret;
1237}
1238
28ab034a
JG
1239static int create_session(const char *name,
1240 xmlNodePtr output_node,
1241 uint64_t live_timer_interval,
1242 const struct config_load_session_override_attr *overrides)
dcf266c0 1243{
fbc3f258
JR
1244 int ret = 0;
1245 enum lttng_error_code ret_code;
1c9a0b0e 1246 struct consumer_output output = {};
dcf266c0 1247 xmlNodePtr consumer_output_node;
cd9adb8b
JG
1248 const char *control_uri = nullptr;
1249 const char *data_uri = nullptr;
1250 const char *path = nullptr;
fbc3f258 1251 struct lttng_session_descriptor *session_descriptor = nullptr;
dcf266c0 1252
a0377dfe 1253 LTTNG_ASSERT(name);
dcf266c0
JG
1254
1255 if (output_node) {
1256 consumer_output_node = xmlFirstElementChild(output_node);
1257 if (!consumer_output_node) {
1258 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1259 goto end;
1260 }
1261
1262 if (strcmp((const char *) consumer_output_node->name,
28ab034a 1263 config_element_consumer_output)) {
dcf266c0 1264 WARN("Invalid output type, expected %s node",
28ab034a 1265 config_element_consumer_output);
dcf266c0
JG
1266 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1267 goto end;
1268 }
1269
1270 ret = process_consumer_output(consumer_output_node, &output);
1271 if (ret) {
1272 goto end;
1273 }
1274 }
1275
21a3f144
JR
1276 control_uri = output.control_uri;
1277 data_uri = output.data_uri;
1278 path = output.path;
1279
1b08cbce
JR
1280 /* Check for override and apply them */
1281 if (overrides) {
1282 if (overrides->path_url) {
1b08cbce 1283 path = overrides->path_url;
21a3f144 1284 /* control/data_uri are null */;
cd9adb8b
JG
1285 control_uri = nullptr;
1286 data_uri = nullptr;
1b08cbce
JR
1287 } else {
1288 if (overrides->ctrl_url) {
1b08cbce 1289 control_uri = overrides->ctrl_url;
21a3f144 1290 /* path is null */
cd9adb8b 1291 path = nullptr;
1b08cbce
JR
1292 }
1293 if (overrides->data_url) {
1b08cbce 1294 data_uri = overrides->data_url;
21a3f144 1295 /* path is null */
cd9adb8b 1296 path = nullptr;
1b08cbce
JR
1297 }
1298 }
1b08cbce
JR
1299 }
1300
1301 if (live_timer_interval != UINT64_MAX && !control_uri && !data_uri) {
dcf266c0
JG
1302 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1303 goto end;
1304 }
1305
1b08cbce 1306 if (control_uri || data_uri) {
dcf266c0
JG
1307 /* network destination */
1308 if (live_timer_interval && live_timer_interval != UINT64_MAX) {
b664f89a
DG
1309 /*
1310 * URLs are provided for sure since the test above make sure that
1311 * with a live timer the data and control URIs are provided. So,
1312 * NULL is passed here and will be set right after.
1313 */
fbc3f258 1314 session_descriptor = lttng_session_descriptor_live_network_create(
28ab034a 1315 name, control_uri, data_uri, live_timer_interval);
dcf266c0 1316 } else {
fbc3f258 1317 session_descriptor = lttng_session_descriptor_network_create(
28ab034a 1318 name, control_uri, data_uri);
dcf266c0 1319 }
95681498 1320
fbc3f258
JR
1321 } else if (path != nullptr) {
1322 session_descriptor = lttng_session_descriptor_local_create(name, path);
dcf266c0 1323 } else {
fbc3f258
JR
1324 /* No output */
1325 session_descriptor = lttng_session_descriptor_create(name);
1326 }
1327
1328 if (session_descriptor == nullptr) {
1329 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1330 goto end;
dcf266c0 1331 }
fbc3f258
JR
1332
1333 ret_code = lttng_create_session_ext(session_descriptor);
1334 if (ret_code != LTTNG_OK) {
1335 ret = -ret_code;
1336 goto end;
1337 }
1338
dcf266c0
JG
1339end:
1340 free(output.path);
1341 free(output.control_uri);
1342 free(output.data_uri);
fbc3f258 1343 lttng_session_descriptor_destroy(session_descriptor);
dcf266c0
JG
1344 return ret;
1345}
c1e83fb4 1346
28ab034a
JG
1347static struct lttng_userspace_probe_location *
1348process_userspace_probe_function_attribute_node(xmlNodePtr attribute_node)
c1e83fb4 1349{
c1e83fb4 1350 xmlNodePtr function_attribute_node;
cd9adb8b
JG
1351 char *function_name = nullptr, *binary_path = nullptr;
1352 struct lttng_userspace_probe_location *location = nullptr;
1353 struct lttng_userspace_probe_location_lookup_method *lookup_method = nullptr;
c1e83fb4
FD
1354
1355 /*
1356 * Process userspace probe location function attributes. The order of
1357 * the fields are not guaranteed so we need to iterate over all fields
1358 * and check at the end if everything we need for this location type is
1359 * there.
1360 */
28ab034a
JG
1361 for (function_attribute_node = xmlFirstElementChild(attribute_node);
1362 function_attribute_node;
1363 function_attribute_node = xmlNextElementSibling(function_attribute_node)) {
c1e83fb4
FD
1364 /* Handle function name, binary path and lookup method. */
1365 if (!strcmp((const char *) function_attribute_node->name,
28ab034a 1366 config_element_userspace_probe_function_location_function_name)) {
717d2dba 1367 function_name = (char *) xmlNodeGetContent(function_attribute_node);
c1e83fb4 1368 if (!function_name) {
c1e83fb4
FD
1369 goto error;
1370 }
1371 } else if (!strcmp((const char *) function_attribute_node->name,
28ab034a 1372 config_element_userspace_probe_location_binary_path)) {
717d2dba 1373 binary_path = (char *) xmlNodeGetContent(function_attribute_node);
c1e83fb4 1374 if (!binary_path) {
c1e83fb4
FD
1375 goto error;
1376 }
1377 } else if (!strcmp((const char *) function_attribute_node->name,
28ab034a 1378 config_element_userspace_probe_lookup)) {
717d2dba 1379 char *lookup_method_name;
c1e83fb4 1380
28ab034a 1381 lookup_method_name = (char *) xmlNodeGetContent(function_attribute_node);
c1e83fb4 1382 if (!lookup_method_name) {
c1e83fb4
FD
1383 goto error;
1384 }
1385
1386 /*
1387 * function_default lookup method defaults to
1388 * function_elf lookup method at the moment.
1389 */
28ab034a
JG
1390 if (!strcmp(lookup_method_name,
1391 config_element_userspace_probe_lookup_function_elf) ||
1392 !strcmp(lookup_method_name,
1393 config_element_userspace_probe_lookup_function_default)) {
1394 lookup_method =
1395 lttng_userspace_probe_location_lookup_method_function_elf_create();
c1e83fb4
FD
1396 if (!lookup_method) {
1397 PERROR("Error creating function default/ELF lookup method");
c1e83fb4
FD
1398 }
1399 } else {
717d2dba
JG
1400 WARN("Unknown function lookup method");
1401 }
1402
1403 free(lookup_method_name);
1404 if (!lookup_method) {
c1e83fb4
FD
1405 goto error;
1406 }
1407 } else {
1408 goto error;
1409 }
1410
1411 /* Check if all the necessary fields were found. */
1412 if (binary_path && function_name && lookup_method) {
717d2dba 1413 /* Ownership of lookup_method is transferred. */
28ab034a
JG
1414 location = lttng_userspace_probe_location_function_create(
1415 binary_path, function_name, lookup_method);
cd9adb8b 1416 lookup_method = nullptr;
717d2dba 1417 goto error;
c1e83fb4
FD
1418 }
1419 }
1420error:
717d2dba 1421 lttng_userspace_probe_location_lookup_method_destroy(lookup_method);
c1e83fb4
FD
1422 free(binary_path);
1423 free(function_name);
c1e83fb4
FD
1424 return location;
1425}
1426
28ab034a
JG
1427static struct lttng_userspace_probe_location *
1428process_userspace_probe_tracepoint_attribute_node(xmlNodePtr attribute_node)
c1e83fb4 1429{
c1e83fb4 1430 xmlNodePtr tracepoint_attribute_node;
cd9adb8b
JG
1431 char *probe_name = nullptr, *provider_name = nullptr, *binary_path = nullptr;
1432 struct lttng_userspace_probe_location *location = nullptr;
1433 struct lttng_userspace_probe_location_lookup_method *lookup_method = nullptr;
c1e83fb4
FD
1434
1435 /*
1436 * Process userspace probe location tracepoint attributes. The order of
1437 * the fields are not guaranteed so we need to iterate over all fields
1438 * and check at the end if everything we need for this location type is
1439 * there.
1440 */
28ab034a
JG
1441 for (tracepoint_attribute_node = xmlFirstElementChild(attribute_node);
1442 tracepoint_attribute_node;
1443 tracepoint_attribute_node = xmlNextElementSibling(tracepoint_attribute_node)) {
c1e83fb4 1444 if (!strcmp((const char *) tracepoint_attribute_node->name,
28ab034a 1445 config_element_userspace_probe_tracepoint_location_probe_name)) {
717d2dba 1446 probe_name = (char *) xmlNodeGetContent(tracepoint_attribute_node);
c1e83fb4 1447 if (!probe_name) {
c1e83fb4
FD
1448 goto error;
1449 }
1450 } else if (!strcmp((const char *) tracepoint_attribute_node->name,
28ab034a 1451 config_element_userspace_probe_tracepoint_location_provider_name)) {
717d2dba 1452 provider_name = (char *) xmlNodeGetContent(tracepoint_attribute_node);
c1e83fb4 1453 if (!provider_name) {
c1e83fb4
FD
1454 goto error;
1455 }
1456 } else if (!strcmp((const char *) tracepoint_attribute_node->name,
28ab034a 1457 config_element_userspace_probe_location_binary_path)) {
717d2dba 1458 binary_path = (char *) xmlNodeGetContent(tracepoint_attribute_node);
c1e83fb4 1459 if (!binary_path) {
c1e83fb4
FD
1460 goto error;
1461 }
1462 } else if (!strcmp((const char *) tracepoint_attribute_node->name,
28ab034a 1463 config_element_userspace_probe_lookup)) {
717d2dba 1464 char *lookup_method_name;
c1e83fb4 1465
28ab034a 1466 lookup_method_name = (char *) xmlNodeGetContent(tracepoint_attribute_node);
c1e83fb4 1467 if (!lookup_method_name) {
c1e83fb4
FD
1468 goto error;
1469 }
1470
1471 if (!strcmp(lookup_method_name,
28ab034a 1472 config_element_userspace_probe_lookup_tracepoint_sdt)) {
c1e83fb4
FD
1473 lookup_method =
1474 lttng_userspace_probe_location_lookup_method_tracepoint_sdt_create();
1475 if (!lookup_method) {
1476 PERROR("Error creating tracepoint SDT lookup method");
c1e83fb4
FD
1477 }
1478 } else {
717d2dba
JG
1479 WARN("Unknown tracepoint lookup method");
1480 }
1481
1482 free(lookup_method_name);
1483 if (!lookup_method) {
c1e83fb4
FD
1484 goto error;
1485 }
1486 } else {
717d2dba 1487 WARN("Unknown tracepoint attribute");
c1e83fb4
FD
1488 goto error;
1489 }
1490
1491 /* Check if all the necessary fields were found. */
1492 if (binary_path && provider_name && probe_name && lookup_method) {
717d2dba 1493 /* Ownership of lookup_method is transferred. */
28ab034a
JG
1494 location = lttng_userspace_probe_location_tracepoint_create(
1495 binary_path, provider_name, probe_name, lookup_method);
cd9adb8b 1496 lookup_method = nullptr;
717d2dba 1497 goto error;
c1e83fb4
FD
1498 }
1499 }
1500error:
717d2dba 1501 lttng_userspace_probe_location_lookup_method_destroy(lookup_method);
c1e83fb4 1502 free(binary_path);
c1e83fb4 1503 free(provider_name);
717d2dba 1504 free(probe_name);
c1e83fb4
FD
1505 return location;
1506}
1507
28ab034a
JG
1508static int process_probe_attribute_node(xmlNodePtr probe_attribute_node,
1509 struct lttng_event_probe_attr *attr)
dcf266c0
JG
1510{
1511 int ret;
1512
a0377dfe
FD
1513 LTTNG_ASSERT(probe_attribute_node);
1514 LTTNG_ASSERT(attr);
dcf266c0 1515
28ab034a 1516 if (!strcmp((const char *) probe_attribute_node->name, config_element_address)) {
dcf266c0
JG
1517 xmlChar *content;
1518 uint64_t addr = 0;
1519
1520 /* addr */
1521 content = xmlNodeGetContent(probe_attribute_node);
1522 if (!content) {
1523 ret = -LTTNG_ERR_NOMEM;
1524 goto end;
1525 }
1526
1527 ret = parse_uint(content, &addr);
1528 free(content);
1529 if (ret) {
1530 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1531 goto end;
1532 }
1533
1534 attr->addr = addr;
28ab034a 1535 } else if (!strcmp((const char *) probe_attribute_node->name, config_element_offset)) {
dcf266c0
JG
1536 xmlChar *content;
1537 uint64_t offset = 0;
1538
1539 /* offset */
1540 content = xmlNodeGetContent(probe_attribute_node);
1541 if (!content) {
1542 ret = -LTTNG_ERR_NOMEM;
1543 goto end;
1544 }
1545
1546 ret = parse_uint(content, &offset);
1547 free(content);
1548 if (ret) {
1549 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1550 goto end;
1551 }
1552
1553 attr->offset = offset;
28ab034a 1554 } else if (!strcmp((const char *) probe_attribute_node->name, config_element_symbol_name)) {
dcf266c0 1555 xmlChar *content;
dcf266c0
JG
1556
1557 /* symbol_name */
1558 content = xmlNodeGetContent(probe_attribute_node);
1559 if (!content) {
1560 ret = -LTTNG_ERR_NOMEM;
1561 goto end;
1562 }
1563
28ab034a
JG
1564 ret = lttng_strncpy(
1565 attr->symbol_name, (const char *) content, LTTNG_SYMBOL_NAME_LEN);
d2e67842 1566 if (ret == -1) {
28ab034a
JG
1567 ERR("symbol name \"%s\"'s length (%zu) exceeds the maximal permitted length (%d) in session configuration",
1568 (const char *) content,
1569 strlen((const char *) content),
1570 LTTNG_SYMBOL_NAME_LEN);
dcf266c0
JG
1571 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1572 free(content);
1573 goto end;
1574 }
dcf266c0
JG
1575 free(content);
1576 }
1577 ret = 0;
1578end:
1579 return ret;
1580}
1581
28ab034a
JG
1582static int process_event_node(xmlNodePtr event_node,
1583 struct lttng_handle *handle,
1584 const char *channel_name,
1585 const enum process_event_node_phase phase)
dcf266c0 1586{
d7b645e2 1587 int ret = 0, i;
dcf266c0 1588 xmlNodePtr node;
91744e14 1589 struct lttng_event *event;
cd9adb8b 1590 char **exclusions = nullptr;
dcf266c0 1591 unsigned long exclusion_count = 0;
cd9adb8b 1592 char *filter_expression = nullptr;
dcf266c0 1593
a0377dfe
FD
1594 LTTNG_ASSERT(event_node);
1595 LTTNG_ASSERT(handle);
1596 LTTNG_ASSERT(channel_name);
dcf266c0 1597
91744e14
FD
1598 event = lttng_event_create();
1599 if (!event) {
1600 ret = -LTTNG_ERR_NOMEM;
1601 goto end;
1602 }
dcf266c0 1603
f40eba3d 1604 /* Initialize default log level which varies by domain */
28ab034a 1605 switch (handle->domain.type) {
f40eba3d 1606 case LTTNG_DOMAIN_JUL:
91744e14 1607 event->loglevel = LTTNG_LOGLEVEL_JUL_ALL;
f40eba3d
JG
1608 break;
1609 case LTTNG_DOMAIN_LOG4J:
91744e14 1610 event->loglevel = LTTNG_LOGLEVEL_LOG4J_ALL;
f40eba3d
JG
1611 break;
1612 case LTTNG_DOMAIN_PYTHON:
91744e14 1613 event->loglevel = LTTNG_LOGLEVEL_PYTHON_DEBUG;
f40eba3d
JG
1614 break;
1615 case LTTNG_DOMAIN_UST:
1616 case LTTNG_DOMAIN_KERNEL:
91744e14 1617 event->loglevel = LTTNG_LOGLEVEL_DEBUG;
f40eba3d
JG
1618 break;
1619 default:
a0377dfe 1620 abort();
f40eba3d
JG
1621 }
1622
28ab034a 1623 for (node = xmlFirstElementChild(event_node); node; node = xmlNextElementSibling(node)) {
dcf266c0
JG
1624 if (!strcmp((const char *) node->name, config_element_name)) {
1625 xmlChar *content;
dcf266c0
JG
1626
1627 /* name */
1628 content = xmlNodeGetContent(node);
1629 if (!content) {
1630 ret = -LTTNG_ERR_NOMEM;
1631 goto end;
1632 }
1633
28ab034a
JG
1634 ret = lttng_strncpy(
1635 event->name, (const char *) content, LTTNG_SYMBOL_NAME_LEN);
d2e67842
JG
1636 if (ret == -1) {
1637 WARN("Event \"%s\"'s name length (%zu) exceeds the maximal permitted length (%d) in session configuration",
28ab034a
JG
1638 (const char *) content,
1639 strlen((const char *) content),
1640 LTTNG_SYMBOL_NAME_LEN);
dcf266c0
JG
1641 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1642 free(content);
1643 goto end;
1644 }
dcf266c0 1645 free(content);
28ab034a 1646 } else if (!strcmp((const char *) node->name, config_element_enabled)) {
dcf266c0
JG
1647 xmlChar *content = xmlNodeGetContent(node);
1648
1649 /* enabled */
1650 if (!content) {
1651 ret = -LTTNG_ERR_NOMEM;
1652 goto end;
1653 }
1654
91744e14 1655 ret = parse_bool(content, &event->enabled);
dcf266c0
JG
1656 free(content);
1657 if (ret) {
1658 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1659 goto end;
1660 }
28ab034a 1661 } else if (!strcmp((const char *) node->name, config_element_type)) {
dcf266c0
JG
1662 xmlChar *content = xmlNodeGetContent(node);
1663
1664 /* type */
1665 if (!content) {
1666 ret = -LTTNG_ERR_NOMEM;
1667 goto end;
1668 }
1669
1670 ret = get_event_type(content);
1671 free(content);
1672 if (ret < 0) {
1673 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1674 goto end;
1675 }
1676
3afa94ae 1677 event->type = (lttng_event_type) ret;
28ab034a 1678 } else if (!strcmp((const char *) node->name, config_element_loglevel_type)) {
dcf266c0
JG
1679 xmlChar *content = xmlNodeGetContent(node);
1680
1681 /* loglevel_type */
1682 if (!content) {
1683 ret = -LTTNG_ERR_NOMEM;
1684 goto end;
1685 }
1686
1687 ret = get_loglevel_type(content);
1688 free(content);
1689 if (ret < 0) {
1690 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1691 goto end;
1692 }
1693
3afa94ae 1694 event->loglevel_type = (lttng_loglevel_type) ret;
28ab034a 1695 } else if (!strcmp((const char *) node->name, config_element_loglevel)) {
dcf266c0
JG
1696 xmlChar *content;
1697 int64_t loglevel = 0;
1698
1699 /* loglevel */
1700 content = xmlNodeGetContent(node);
1701 if (!content) {
1702 ret = -LTTNG_ERR_NOMEM;
1703 goto end;
1704 }
1705
1706 ret = parse_int(content, &loglevel);
1707 free(content);
1708 if (ret) {
1709 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1710 goto end;
1711 }
1712
1713 if (loglevel > INT_MAX || loglevel < INT_MIN) {
1714 WARN("loglevel out of range.");
1715 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1716 goto end;
1717 }
1718
91744e14 1719 event->loglevel = loglevel;
28ab034a
JG
1720 } else if (!strcmp((const char *) node->name, config_element_filter)) {
1721 xmlChar *content = xmlNodeGetContent(node);
dcf266c0
JG
1722
1723 /* filter */
1724 if (!content) {
1725 ret = -LTTNG_ERR_NOMEM;
1726 goto end;
1727 }
1728
02d8ac3d 1729 free(filter_expression);
dcf266c0
JG
1730 filter_expression = strdup((char *) content);
1731 free(content);
1732 if (!filter_expression) {
1733 ret = -LTTNG_ERR_NOMEM;
1734 goto end;
1735 }
28ab034a 1736 } else if (!strcmp((const char *) node->name, config_element_exclusions)) {
dcf266c0
JG
1737 xmlNodePtr exclusion_node;
1738 int exclusion_index = 0;
1739
1740 /* exclusions */
1741 if (exclusions) {
1742 /*
1743 * Exclusions has already been initialized,
1744 * invalid file.
1745 */
1746 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1747 goto end;
1748 }
1749
1750 exclusion_count = xmlChildElementCount(node);
1751 if (!exclusion_count) {
1752 continue;
1753 }
1754
64803277 1755 exclusions = calloc<char *>(exclusion_count);
dcf266c0
JG
1756 if (!exclusions) {
1757 exclusion_count = 0;
1758 ret = -LTTNG_ERR_NOMEM;
1759 goto end;
1760 }
1761
1762 for (exclusion_node = xmlFirstElementChild(node); exclusion_node;
28ab034a
JG
1763 exclusion_node = xmlNextElementSibling(exclusion_node)) {
1764 xmlChar *content = xmlNodeGetContent(exclusion_node);
dcf266c0
JG
1765
1766 if (!content) {
1767 ret = -LTTNG_ERR_NOMEM;
1768 goto end;
1769 }
1770
1771 exclusions[exclusion_index] = strdup((const char *) content);
1772 free(content);
1773 if (!exclusions[exclusion_index]) {
1774 ret = -LTTNG_ERR_NOMEM;
1775 goto end;
1776 }
1777 exclusion_index++;
1778 }
1779
91744e14 1780 event->exclusion = 1;
28ab034a 1781 } else if (!strcmp((const char *) node->name, config_element_attributes)) {
dcf266c0
JG
1782 xmlNodePtr attribute_node = xmlFirstElementChild(node);
1783
1784 /* attributes */
1785 if (!attribute_node) {
1786 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1787 goto end;
1788 }
1789
c1e83fb4 1790 if (!strcmp((const char *) attribute_node->name,
28ab034a 1791 config_element_probe_attributes)) {
dcf266c0
JG
1792 xmlNodePtr probe_attribute_node;
1793
1794 /* probe_attributes */
28ab034a
JG
1795 for (probe_attribute_node = xmlFirstElementChild(attribute_node);
1796 probe_attribute_node;
1797 probe_attribute_node =
1798 xmlNextElementSibling(probe_attribute_node)) {
dcf266c0 1799 ret = process_probe_attribute_node(probe_attribute_node,
28ab034a 1800 &event->attr.probe);
dcf266c0
JG
1801 if (ret) {
1802 goto end;
1803 }
1804 }
c1e83fb4 1805 } else if (!strcmp((const char *) attribute_node->name,
28ab034a 1806 config_element_function_attributes)) {
dcf266c0
JG
1807 size_t sym_len;
1808 xmlChar *content;
1809 xmlNodePtr symbol_node = xmlFirstElementChild(attribute_node);
1810
1811 /* function_attributes */
1812 content = xmlNodeGetContent(symbol_node);
1813 if (!content) {
1814 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1815 goto end;
1816 }
1817
1818 sym_len = strlen((char *) content);
1819 if (sym_len >= LTTNG_SYMBOL_NAME_LEN) {
1820 WARN("Function name too long.");
1821 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1822 free(content);
1823 goto end;
1824 }
1825
d2e67842 1826 ret = lttng_strncpy(
28ab034a 1827 event->attr.ftrace.symbol_name, (char *) content, sym_len);
d2e67842
JG
1828 if (ret == -1) {
1829 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1830 free(content);
1831 goto end;
1832 }
dcf266c0 1833 free(content);
c1e83fb4 1834 } else if (!strcmp((const char *) attribute_node->name,
28ab034a 1835 config_element_userspace_probe_tracepoint_attributes)) {
c1e83fb4
FD
1836 struct lttng_userspace_probe_location *location;
1837
28ab034a
JG
1838 location = process_userspace_probe_tracepoint_attribute_node(
1839 attribute_node);
c1e83fb4
FD
1840 if (!location) {
1841 WARN("Error processing userspace probe tracepoint attribute");
1842 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1843 goto end;
1844 }
28ab034a 1845 ret = lttng_event_set_userspace_probe_location(event, location);
c1e83fb4
FD
1846 if (ret) {
1847 WARN("Error setting userspace probe location field");
28ab034a 1848 lttng_userspace_probe_location_destroy(location);
c1e83fb4
FD
1849 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1850 goto end;
1851 }
1852 } else if (!strcmp((const char *) attribute_node->name,
28ab034a 1853 config_element_userspace_probe_function_attributes)) {
c1e83fb4
FD
1854 struct lttng_userspace_probe_location *location;
1855
28ab034a
JG
1856 location = process_userspace_probe_function_attribute_node(
1857 attribute_node);
c1e83fb4
FD
1858 if (!location) {
1859 WARN("Error processing userspace probe function attribute");
1860 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1861 goto end;
1862 }
1863
28ab034a 1864 ret = lttng_event_set_userspace_probe_location(event, location);
c1e83fb4
FD
1865 if (ret) {
1866 WARN("Error setting userspace probe location field");
28ab034a 1867 lttng_userspace_probe_location_destroy(location);
c1e83fb4
FD
1868 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1869 goto end;
1870 }
1871 } else {
1872 /* Unknown event attribute. */
1873 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1874 goto end;
dcf266c0
JG
1875 }
1876 }
1877 }
1878
91744e14 1879 if ((event->enabled && phase == ENABLE) || phase == CREATION) {
28ab034a
JG
1880 ret = lttng_enable_event_with_exclusions(
1881 handle, event, channel_name, filter_expression, exclusion_count, exclusions);
d7b645e2 1882 if (ret < 0) {
91744e14 1883 WARN("Enabling event (name:%s) on load failed.", event->name);
d7b645e2
JR
1884 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1885 goto end;
1886 }
065321e9 1887 }
d2e67842 1888 ret = 0;
dcf266c0
JG
1889end:
1890 for (i = 0; i < exclusion_count; i++) {
1891 free(exclusions[i]);
1892 }
1893
b33f872b 1894 lttng_event_destroy(event);
dcf266c0
JG
1895 free(exclusions);
1896 free(filter_expression);
1897 return ret;
1898}
1899
28ab034a
JG
1900static int
1901process_events_node(xmlNodePtr events_node, struct lttng_handle *handle, const char *channel_name)
dcf266c0
JG
1902{
1903 int ret = 0;
d7b645e2 1904 struct lttng_event event;
dcf266c0
JG
1905 xmlNodePtr node;
1906
a0377dfe
FD
1907 LTTNG_ASSERT(events_node);
1908 LTTNG_ASSERT(handle);
1909 LTTNG_ASSERT(channel_name);
dcf266c0 1910
28ab034a 1911 for (node = xmlFirstElementChild(events_node); node; node = xmlNextElementSibling(node)) {
d7b645e2 1912 ret = process_event_node(node, handle, channel_name, CREATION);
dcf266c0
JG
1913 if (ret) {
1914 goto end;
1915 }
1916 }
d7b645e2
JR
1917
1918 /*
1919 * Disable all events to enable only the necessary events.
1920 * Limitations regarding lttng_disable_events and tuple descriptor
1921 * force this approach.
1922 */
1923 memset(&event, 0, sizeof(event));
1924 event.loglevel = -1;
1925 event.type = LTTNG_EVENT_ALL;
cd9adb8b 1926 ret = lttng_disable_event_ext(handle, &event, channel_name, nullptr);
d7b645e2
JR
1927 if (ret) {
1928 goto end;
1929 }
1930
28ab034a 1931 for (node = xmlFirstElementChild(events_node); node; node = xmlNextElementSibling(node)) {
d7b645e2
JR
1932 ret = process_event_node(node, handle, channel_name, ENABLE);
1933 if (ret) {
1934 goto end;
1935 }
1936 }
1937
dcf266c0
JG
1938end:
1939 return ret;
1940}
1941
28ab034a
JG
1942static int process_channel_attr_node(xmlNodePtr attr_node,
1943 struct lttng_channel *channel,
1944 xmlNodePtr *contexts_node,
1945 xmlNodePtr *events_node)
dcf266c0
JG
1946{
1947 int ret;
1948
a0377dfe
FD
1949 LTTNG_ASSERT(attr_node);
1950 LTTNG_ASSERT(channel);
1951 LTTNG_ASSERT(contexts_node);
1952 LTTNG_ASSERT(events_node);
dcf266c0
JG
1953
1954 if (!strcmp((const char *) attr_node->name, config_element_name)) {
1955 xmlChar *content;
dcf266c0
JG
1956
1957 /* name */
1958 content = xmlNodeGetContent(attr_node);
1959 if (!content) {
1960 ret = -LTTNG_ERR_NOMEM;
1961 goto end;
1962 }
1963
28ab034a 1964 ret = lttng_strncpy(channel->name, (const char *) content, LTTNG_SYMBOL_NAME_LEN);
d2e67842
JG
1965 if (ret == -1) {
1966 WARN("Channel \"%s\"'s name length (%zu) exceeds the maximal permitted length (%d) in session configuration",
28ab034a
JG
1967 (const char *) content,
1968 strlen((const char *) content),
1969 LTTNG_SYMBOL_NAME_LEN);
dcf266c0
JG
1970 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1971 free(content);
1972 goto end;
1973 }
dcf266c0 1974 free(content);
28ab034a 1975 } else if (!strcmp((const char *) attr_node->name, config_element_enabled)) {
dcf266c0
JG
1976 xmlChar *content;
1977 int enabled;
1978
1979 /* enabled */
1980 content = xmlNodeGetContent(attr_node);
1981 if (!content) {
1982 ret = -LTTNG_ERR_NOMEM;
1983 goto end;
1984 }
1985
1986 ret = parse_bool(content, &enabled);
1987 free(content);
1988 if (ret) {
1989 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
1990 goto end;
1991 }
1992
1993 channel->enabled = enabled;
28ab034a 1994 } else if (!strcmp((const char *) attr_node->name, config_element_overwrite_mode)) {
dcf266c0
JG
1995 xmlChar *content;
1996
1997 /* overwrite_mode */
1998 content = xmlNodeGetContent(attr_node);
1999 if (!content) {
2000 ret = -LTTNG_ERR_NOMEM;
2001 goto end;
2002 }
2003
2004 ret = get_overwrite_mode(content);
2005 free(content);
2006 if (ret < 0) {
2007 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2008 goto end;
2009 }
2010
2011 channel->attr.overwrite = ret;
28ab034a 2012 } else if (!strcmp((const char *) attr_node->name, config_element_subbuf_size)) {
dcf266c0
JG
2013 xmlChar *content;
2014
2015 /* subbuffer_size */
2016 content = xmlNodeGetContent(attr_node);
2017 if (!content) {
2018 ret = -LTTNG_ERR_NOMEM;
2019 goto end;
2020 }
2021
2022 ret = parse_uint(content, &channel->attr.subbuf_size);
2023 free(content);
2024 if (ret) {
2025 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2026 goto end;
2027 }
28ab034a 2028 } else if (!strcmp((const char *) attr_node->name, config_element_num_subbuf)) {
dcf266c0
JG
2029 xmlChar *content;
2030
2031 /* subbuffer_count */
2032 content = xmlNodeGetContent(attr_node);
2033 if (!content) {
2034 ret = -LTTNG_ERR_NOMEM;
2035 goto end;
2036 }
2037
2038 ret = parse_uint(content, &channel->attr.num_subbuf);
2039 free(content);
2040 if (ret) {
2041 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2042 goto end;
2043 }
28ab034a 2044 } else if (!strcmp((const char *) attr_node->name, config_element_switch_timer_interval)) {
dcf266c0
JG
2045 xmlChar *content;
2046 uint64_t switch_timer_interval = 0;
2047
2048 /* switch_timer_interval */
2049 content = xmlNodeGetContent(attr_node);
2050 if (!content) {
2051 ret = -LTTNG_ERR_NOMEM;
2052 goto end;
2053 }
2054
2055 ret = parse_uint(content, &switch_timer_interval);
2056 free(content);
2057 if (ret) {
2058 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2059 goto end;
2060 }
2061
2062 if (switch_timer_interval > UINT_MAX) {
2063 WARN("switch_timer_interval out of range.");
2064 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2065 goto end;
2066 }
2067
28ab034a
JG
2068 channel->attr.switch_timer_interval = switch_timer_interval;
2069 } else if (!strcmp((const char *) attr_node->name, config_element_read_timer_interval)) {
dcf266c0
JG
2070 xmlChar *content;
2071 uint64_t read_timer_interval = 0;
2072
2073 /* read_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, &read_timer_interval);
2081 free(content);
2082 if (ret) {
2083 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2084 goto end;
2085 }
2086
2087 if (read_timer_interval > UINT_MAX) {
2088 WARN("read_timer_interval out of range.");
2089 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2090 goto end;
2091 }
2092
28ab034a
JG
2093 channel->attr.read_timer_interval = read_timer_interval;
2094 } else if (!strcmp((const char *) attr_node->name, config_element_output_type)) {
dcf266c0
JG
2095 xmlChar *content;
2096
2097 /* output_type */
2098 content = xmlNodeGetContent(attr_node);
2099 if (!content) {
2100 ret = -LTTNG_ERR_NOMEM;
2101 goto end;
2102 }
2103
2104 ret = get_output_type(content);
2105 free(content);
2106 if (ret < 0) {
2107 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2108 goto end;
2109 }
2110
3afa94ae 2111 channel->attr.output = (lttng_event_output) ret;
28ab034a 2112 } else if (!strcmp((const char *) attr_node->name, config_element_tracefile_size)) {
dcf266c0
JG
2113 xmlChar *content;
2114
2115 /* tracefile_size */
2116 content = xmlNodeGetContent(attr_node);
2117 if (!content) {
2118 ret = -LTTNG_ERR_NOMEM;
2119 goto end;
2120 }
2121
2122 ret = parse_uint(content, &channel->attr.tracefile_size);
2123 free(content);
2124 if (ret) {
2125 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2126 goto end;
2127 }
28ab034a 2128 } else if (!strcmp((const char *) attr_node->name, config_element_tracefile_count)) {
dcf266c0
JG
2129 xmlChar *content;
2130
2131 /* tracefile_count */
2132 content = xmlNodeGetContent(attr_node);
2133 if (!content) {
2134 ret = -LTTNG_ERR_NOMEM;
2135 goto end;
2136 }
2137
2138 ret = parse_uint(content, &channel->attr.tracefile_count);
2139 free(content);
2140 if (ret) {
2141 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2142 goto end;
2143 }
28ab034a 2144 } else if (!strcmp((const char *) attr_node->name, config_element_live_timer_interval)) {
dcf266c0
JG
2145 xmlChar *content;
2146 uint64_t live_timer_interval = 0;
2147
2148 /* live_timer_interval */
2149 content = xmlNodeGetContent(attr_node);
2150 if (!content) {
2151 ret = -LTTNG_ERR_NOMEM;
2152 goto end;
2153 }
2154
2155 ret = parse_uint(content, &live_timer_interval);
2156 free(content);
2157 if (ret) {
2158 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2159 goto end;
2160 }
2161
2162 if (live_timer_interval > UINT_MAX) {
2163 WARN("live_timer_interval out of range.");
2164 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2165 goto end;
2166 }
2167
28ab034a
JG
2168 channel->attr.live_timer_interval = live_timer_interval;
2169 } else if (!strcmp((const char *) attr_node->name, config_element_monitor_timer_interval)) {
4fc2b126
JR
2170 xmlChar *content;
2171 uint64_t monitor_timer_interval = 0;
2172
2173 /* monitor_timer_interval */
2174 content = xmlNodeGetContent(attr_node);
2175 if (!content) {
2176 ret = -LTTNG_ERR_NOMEM;
2177 goto end;
2178 }
2179
2180 ret = parse_uint(content, &monitor_timer_interval);
2181 free(content);
2182 if (ret) {
2183 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2184 goto end;
2185 }
2186
28ab034a 2187 ret = lttng_channel_set_monitor_timer_interval(channel, monitor_timer_interval);
4fc2b126
JR
2188 if (ret) {
2189 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2190 goto end;
2191 }
28ab034a 2192 } else if (!strcmp((const char *) attr_node->name, config_element_blocking_timeout)) {
275472aa
JR
2193 xmlChar *content;
2194 int64_t blocking_timeout = 0;
2195
2196 /* blocking_timeout */
2197 content = xmlNodeGetContent(attr_node);
2198 if (!content) {
2199 ret = -LTTNG_ERR_NOMEM;
2200 goto end;
2201 }
2202
2203 ret = parse_int(content, &blocking_timeout);
2204 free(content);
2205 if (ret) {
2206 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2207 goto end;
2208 }
2209
28ab034a 2210 ret = lttng_channel_set_blocking_timeout(channel, blocking_timeout);
275472aa
JR
2211 if (ret) {
2212 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2213 goto end;
2214 }
28ab034a 2215 } else if (!strcmp((const char *) attr_node->name, config_element_events)) {
dcf266c0
JG
2216 /* events */
2217 *events_node = attr_node;
2218 } else {
2219 /* contexts */
2220 *contexts_node = attr_node;
2221 }
2222 ret = 0;
2223end:
2224 return ret;
2225}
2226
28ab034a
JG
2227static int
2228process_context_node(xmlNodePtr context_node, struct lttng_handle *handle, const char *channel_name)
dcf266c0
JG
2229{
2230 int ret;
2231 struct lttng_event_context context;
2232 xmlNodePtr context_child_node = xmlFirstElementChild(context_node);
2233
a0377dfe
FD
2234 LTTNG_ASSERT(handle);
2235 LTTNG_ASSERT(channel_name);
dcf266c0
JG
2236
2237 if (!context_child_node) {
2238 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2239 goto end;
2240 }
2241
2242 memset(&context, 0, sizeof(context));
2243
28ab034a 2244 if (!strcmp((const char *) context_child_node->name, config_element_type)) {
dcf266c0
JG
2245 /* type */
2246 xmlChar *content = xmlNodeGetContent(context_child_node);
045fc617 2247
dcf266c0
JG
2248 if (!content) {
2249 ret = -LTTNG_ERR_NOMEM;
2250 goto end;
2251 }
2252
2253 ret = get_context_type(content);
2254 free(content);
2255 if (ret < 0) {
2256 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2257 goto end;
2258 }
2259
3afa94ae 2260 context.ctx = (lttng_event_context_type) ret;
28ab034a 2261 } else if (!strcmp((const char *) context_child_node->name, config_element_context_perf)) {
045fc617 2262 /* perf */
dcf266c0
JG
2263 xmlNodePtr perf_attr_node;
2264
14ce5bd8
JG
2265 context.ctx = handle->domain.type == LTTNG_DOMAIN_KERNEL ?
2266 LTTNG_EVENT_CONTEXT_PERF_CPU_COUNTER :
2267 LTTNG_EVENT_CONTEXT_PERF_THREAD_COUNTER;
28ab034a
JG
2268 for (perf_attr_node = xmlFirstElementChild(context_child_node); perf_attr_node;
2269 perf_attr_node = xmlNextElementSibling(perf_attr_node)) {
2270 if (!strcmp((const char *) perf_attr_node->name, config_element_type)) {
dcf266c0
JG
2271 xmlChar *content;
2272 uint64_t type = 0;
2273
2274 /* type */
2275 content = xmlNodeGetContent(perf_attr_node);
2276 if (!content) {
2277 ret = -LTTNG_ERR_NOMEM;
2278 goto end;
2279 }
2280
2281 ret = parse_uint(content, &type);
2282 free(content);
2283 if (ret) {
2284 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2285 goto end;
2286 }
2287
2288 if (type > UINT32_MAX) {
2289 WARN("perf context type out of range.");
2290 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2291 goto end;
2292 }
2293
2294 context.u.perf_counter.type = type;
2295 } else if (!strcmp((const char *) perf_attr_node->name,
28ab034a 2296 config_element_config)) {
dcf266c0
JG
2297 xmlChar *content;
2298 uint64_t config = 0;
2299
2300 /* config */
2301 content = xmlNodeGetContent(perf_attr_node);
2302 if (!content) {
2303 ret = -LTTNG_ERR_NOMEM;
2304 goto end;
2305 }
2306
2307 ret = parse_uint(content, &config);
2308 free(content);
2309 if (ret) {
2310 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2311 goto end;
2312 }
2313
2314 context.u.perf_counter.config = config;
2315 } else if (!strcmp((const char *) perf_attr_node->name,
28ab034a 2316 config_element_name)) {
dcf266c0 2317 xmlChar *content;
dcf266c0
JG
2318
2319 /* name */
2320 content = xmlNodeGetContent(perf_attr_node);
2321 if (!content) {
2322 ret = -LTTNG_ERR_NOMEM;
2323 goto end;
2324 }
2325
d2e67842 2326 ret = lttng_strncpy(context.u.perf_counter.name,
28ab034a
JG
2327 (const char *) content,
2328 LTTNG_SYMBOL_NAME_LEN);
d2e67842
JG
2329 if (ret == -1) {
2330 WARN("Perf counter \"%s\"'s name length (%zu) exceeds the maximal permitted length (%d) in session configuration",
28ab034a
JG
2331 (const char *) content,
2332 strlen((const char *) content),
2333 LTTNG_SYMBOL_NAME_LEN);
dcf266c0
JG
2334 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2335 free(content);
2336 goto end;
2337 }
dcf266c0
JG
2338 free(content);
2339 }
2340 }
28ab034a 2341 } else if (!strcmp((const char *) context_child_node->name, config_element_context_app)) {
045fc617
JG
2342 /* application context */
2343 xmlNodePtr app_ctx_node;
2344
2345 context.ctx = LTTNG_EVENT_CONTEXT_APP_CONTEXT;
28ab034a
JG
2346 for (app_ctx_node = xmlFirstElementChild(context_child_node); app_ctx_node;
2347 app_ctx_node = xmlNextElementSibling(app_ctx_node)) {
045fc617 2348 xmlChar *content;
28ab034a
JG
2349 char **target = strcmp((const char *) app_ctx_node->name,
2350 config_element_context_app_provider_name) == 0 ?
2351 &context.u.app_ctx.provider_name :
2352 &context.u.app_ctx.ctx_name;
045fc617
JG
2353
2354 content = xmlNodeGetContent(app_ctx_node);
2355 if (!content) {
2356 ret = -LTTNG_ERR_NOMEM;
2357 goto end;
2358 }
2359
2360 *target = (char *) content;
2361 }
2362 } else {
2363 /* Unrecognized context type */
2364 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2365 goto end;
dcf266c0
JG
2366 }
2367
cd9adb8b 2368 ret = lttng_add_context(handle, &context, nullptr, channel_name);
045fc617
JG
2369 if (context.ctx == LTTNG_EVENT_CONTEXT_APP_CONTEXT) {
2370 free(context.u.app_ctx.provider_name);
2371 free(context.u.app_ctx.ctx_name);
2372 }
dcf266c0
JG
2373end:
2374 return ret;
2375}
2376
28ab034a
JG
2377static int process_contexts_node(xmlNodePtr contexts_node,
2378 struct lttng_handle *handle,
2379 const char *channel_name)
dcf266c0
JG
2380{
2381 int ret = 0;
2382 xmlNodePtr context_node;
2383
2384 for (context_node = xmlFirstElementChild(contexts_node); context_node;
28ab034a 2385 context_node = xmlNextElementSibling(context_node)) {
dcf266c0
JG
2386 ret = process_context_node(context_node, handle, channel_name);
2387 if (ret) {
2388 goto end;
2389 }
2390 }
2391end:
2392 return ret;
2393}
2394
159b042f 2395static int get_tracker_elements(enum lttng_process_attr process_attr,
28ab034a
JG
2396 const char **element_id_tracker,
2397 const char **element_value_type,
2398 const char **element_value,
2399 const char **element_value_alias,
2400 const char **element_name)
55c9e7ca
JR
2401{
2402 int ret = 0;
2403
159b042f
JG
2404 switch (process_attr) {
2405 case LTTNG_PROCESS_ATTR_PROCESS_ID:
2406 *element_id_tracker = config_element_process_attr_tracker_pid;
2407 *element_value_type = config_element_process_attr_pid_value;
2408 *element_value = config_element_process_attr_id;
2409 *element_value_alias = config_element_process_attr_id;
cd9adb8b 2410 *element_name = nullptr;
55c9e7ca 2411 break;
159b042f
JG
2412 case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
2413 *element_id_tracker = config_element_process_attr_tracker_vpid;
2414 *element_value_type = config_element_process_attr_vpid_value;
2415 *element_value = config_element_process_attr_id;
cd9adb8b
JG
2416 *element_value_alias = nullptr;
2417 *element_name = nullptr;
55c9e7ca 2418 break;
159b042f
JG
2419 case LTTNG_PROCESS_ATTR_USER_ID:
2420 *element_id_tracker = config_element_process_attr_tracker_uid;
2421 *element_value_type = config_element_process_attr_uid_value;
2422 *element_value = config_element_process_attr_id;
cd9adb8b 2423 *element_value_alias = nullptr;
55c9e7ca
JR
2424 *element_name = config_element_name;
2425 break;
159b042f
JG
2426 case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
2427 *element_id_tracker = config_element_process_attr_tracker_vuid;
2428 *element_value_type = config_element_process_attr_vuid_value;
2429 *element_value = config_element_process_attr_id;
cd9adb8b 2430 *element_value_alias = nullptr;
55c9e7ca
JR
2431 *element_name = config_element_name;
2432 break;
159b042f
JG
2433 case LTTNG_PROCESS_ATTR_GROUP_ID:
2434 *element_id_tracker = config_element_process_attr_tracker_gid;
2435 *element_value_type = config_element_process_attr_gid_value;
2436 *element_value = config_element_process_attr_id;
cd9adb8b 2437 *element_value_alias = nullptr;
55c9e7ca
JR
2438 *element_name = config_element_name;
2439 break;
159b042f
JG
2440 case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
2441 *element_id_tracker = config_element_process_attr_tracker_vgid;
2442 *element_value_type = config_element_process_attr_vgid_value;
2443 *element_value = config_element_process_attr_id;
cd9adb8b 2444 *element_value_alias = nullptr;
55c9e7ca
JR
2445 *element_name = config_element_name;
2446 break;
2447 default:
2448 ret = LTTNG_ERR_INVALID;
2449 }
2450 return ret;
2451}
2452
28ab034a 2453static int process_legacy_pid_tracker_node(xmlNodePtr trackers_node, struct lttng_handle *handle)
f7af9a72
JG
2454{
2455 int ret = 0, child_count;
cd9adb8b 2456 xmlNodePtr targets_node = nullptr;
f7af9a72
JG
2457 xmlNodePtr node;
2458 const char *element_id_tracker;
2459 const char *element_target_id;
2460 const char *element_id;
2461 const char *element_id_alias;
2462 const char *element_name;
2463 enum lttng_error_code tracker_handle_ret_code;
cd9adb8b 2464 struct lttng_process_attr_tracker_handle *tracker_handle = nullptr;
f7af9a72 2465 enum lttng_process_attr_tracker_handle_status status;
28ab034a
JG
2466 const enum lttng_process_attr process_attr = handle->domain.type == LTTNG_DOMAIN_UST ?
2467 LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID :
2468 LTTNG_PROCESS_ATTR_PROCESS_ID;
f7af9a72 2469
a0377dfe 2470 LTTNG_ASSERT(handle);
f7af9a72
JG
2471
2472 tracker_handle_ret_code = lttng_session_get_tracker_handle(
28ab034a 2473 handle->session_name, handle->domain.type, process_attr, &tracker_handle);
f7af9a72
JG
2474 if (tracker_handle_ret_code != LTTNG_OK) {
2475 ret = LTTNG_ERR_INVALID;
2476 goto end;
2477 }
2478
28ab034a
JG
2479 ret = get_tracker_elements(process_attr,
2480 &element_id_tracker,
2481 &element_target_id,
2482 &element_id,
2483 &element_id_alias,
2484 &element_name);
f7af9a72
JG
2485 if (ret) {
2486 goto end;
2487 }
2488
2489 /* Get the targets node */
28ab034a
JG
2490 for (node = xmlFirstElementChild(trackers_node); node; node = xmlNextElementSibling(node)) {
2491 if (!strcmp((const char *) node->name, config_element_tracker_targets_legacy)) {
f7af9a72
JG
2492 targets_node = node;
2493 break;
2494 }
3afa94ae 2495 }
f7af9a72
JG
2496
2497 if (!targets_node) {
2498 ret = LTTNG_ERR_INVALID;
2499 goto end;
2500 }
2501
2502 /* Go through all id target node */
2503 child_count = xmlChildElementCount(targets_node);
2504 status = lttng_process_attr_tracker_handle_set_tracking_policy(
28ab034a
JG
2505 tracker_handle,
2506 child_count == 0 ? LTTNG_TRACKING_POLICY_EXCLUDE_ALL :
2507 LTTNG_TRACKING_POLICY_INCLUDE_SET);
f7af9a72
JG
2508 if (status != LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_OK) {
2509 ret = LTTNG_ERR_UNK;
2510 goto end;
2511 }
2512
2513 /* Add all tracked values. */
28ab034a 2514 for (node = xmlFirstElementChild(targets_node); node; node = xmlNextElementSibling(node)) {
f7af9a72
JG
2515 xmlNodePtr pid_target_node = node;
2516
2517 /* get pid_target node and track it */
2518 for (node = xmlFirstElementChild(pid_target_node); node;
28ab034a
JG
2519 node = xmlNextElementSibling(node)) {
2520 if (!strcmp((const char *) node->name, config_element_tracker_pid_legacy)) {
f7af9a72
JG
2521 int64_t id;
2522 xmlChar *content = xmlNodeGetContent(node);
2523
2524 if (!content) {
2525 ret = LTTNG_ERR_LOAD_INVALID_CONFIG;
2526 goto end;
2527 }
2528
2529 ret = parse_int(content, &id);
2530 free(content);
2531 if (ret) {
2532 ret = LTTNG_ERR_LOAD_INVALID_CONFIG;
2533 goto end;
2534 }
2535
2536 switch (process_attr) {
2537 case LTTNG_PROCESS_ATTR_PROCESS_ID:
28ab034a
JG
2538 status =
2539 lttng_process_attr_process_id_tracker_handle_add_pid(
2540 tracker_handle, (pid_t) id);
f7af9a72
JG
2541 break;
2542 case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
28ab034a
JG
2543 status =
2544 lttng_process_attr_virtual_process_id_tracker_handle_add_pid(
2545 tracker_handle, (pid_t) id);
f7af9a72
JG
2546 break;
2547 default:
2548 ret = LTTNG_ERR_INVALID;
2549 goto end;
2550 }
2551 }
2552 switch (status) {
2553 case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_OK:
2554 continue;
2555 case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_INVALID:
2556 ret = LTTNG_ERR_INVALID;
2557 break;
2558 case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_EXISTS:
2559 ret = LTTNG_ERR_PROCESS_ATTR_EXISTS;
2560 break;
2561 case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_MISSING:
2562 ret = LTTNG_ERR_PROCESS_ATTR_MISSING;
2563 break;
2564 case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_ERROR:
2565 case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_COMMUNICATION_ERROR:
2566 default:
2567 ret = LTTNG_ERR_UNK;
2568 goto end;
2569 }
2570 }
2571 node = pid_target_node;
2572 }
2573
2574end:
2575 lttng_process_attr_tracker_handle_destroy(tracker_handle);
2576 return ret;
28ab034a 2577}
f7af9a72 2578
55c9e7ca 2579static int process_id_tracker_node(xmlNodePtr id_tracker_node,
28ab034a
JG
2580 struct lttng_handle *handle,
2581 enum lttng_process_attr process_attr)
847a5916 2582{
159b042f 2583 int ret = 0, child_count;
cd9adb8b 2584 xmlNodePtr values_node = nullptr;
847a5916 2585 xmlNodePtr node;
55c9e7ca
JR
2586 const char *element_id_tracker;
2587 const char *element_target_id;
2588 const char *element_id;
2589 const char *element_id_alias;
2590 const char *element_name;
159b042f 2591 enum lttng_error_code tracker_handle_ret_code;
cd9adb8b 2592 struct lttng_process_attr_tracker_handle *tracker_handle = nullptr;
159b042f 2593 enum lttng_process_attr_tracker_handle_status status;
847a5916 2594
a0377dfe
FD
2595 LTTNG_ASSERT(handle);
2596 LTTNG_ASSERT(id_tracker_node);
55c9e7ca 2597
159b042f 2598 tracker_handle_ret_code = lttng_session_get_tracker_handle(
28ab034a 2599 handle->session_name, handle->domain.type, process_attr, &tracker_handle);
159b042f
JG
2600 if (tracker_handle_ret_code != LTTNG_OK) {
2601 ret = LTTNG_ERR_INVALID;
2602 goto end;
2603 }
2604
28ab034a
JG
2605 ret = get_tracker_elements(process_attr,
2606 &element_id_tracker,
2607 &element_target_id,
2608 &element_id,
2609 &element_id_alias,
2610 &element_name);
55c9e7ca 2611 if (ret) {
159b042f 2612 goto end;
55c9e7ca
JR
2613 }
2614
f7af9a72 2615 /* get the values node */
55c9e7ca 2616 for (node = xmlFirstElementChild(id_tracker_node); node;
28ab034a
JG
2617 node = xmlNextElementSibling(node)) {
2618 if (!strcmp((const char *) node->name, config_element_process_attr_values)) {
f7af9a72 2619 values_node = node;
847a5916
JR
2620 break;
2621 }
2622 }
2623
f7af9a72 2624 if (!values_node) {
847a5916
JR
2625 ret = LTTNG_ERR_INVALID;
2626 goto end;
2627 }
2628
55c9e7ca 2629 /* Go through all id target node */
f7af9a72 2630 child_count = xmlChildElementCount(values_node);
159b042f 2631 status = lttng_process_attr_tracker_handle_set_tracking_policy(
28ab034a
JG
2632 tracker_handle,
2633 child_count == 0 ? LTTNG_TRACKING_POLICY_EXCLUDE_ALL :
2634 LTTNG_TRACKING_POLICY_INCLUDE_SET);
159b042f
JG
2635 if (status != LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_OK) {
2636 ret = LTTNG_ERR_UNK;
2637 goto end;
847a5916 2638 }
159b042f
JG
2639
2640 /* Add all tracked values. */
28ab034a 2641 for (node = xmlFirstElementChild(values_node); node; node = xmlNextElementSibling(node)) {
55c9e7ca 2642 xmlNodePtr id_target_node = node;
847a5916 2643
55c9e7ca
JR
2644 /* get id node and track it */
2645 for (node = xmlFirstElementChild(id_target_node); node;
28ab034a 2646 node = xmlNextElementSibling(node)) {
55c9e7ca 2647 if (!strcmp((const char *) node->name, element_id) ||
28ab034a
JG
2648 (element_id_alias &&
2649 !strcmp((const char *) node->name, element_id_alias))) {
55c9e7ca 2650 int64_t id;
159b042f 2651 xmlChar *content = xmlNodeGetContent(node);
847a5916 2652
847a5916
JR
2653 if (!content) {
2654 ret = LTTNG_ERR_LOAD_INVALID_CONFIG;
2655 goto end;
2656 }
2657
55c9e7ca 2658 ret = parse_int(content, &id);
847a5916
JR
2659 free(content);
2660 if (ret) {
2661 ret = LTTNG_ERR_LOAD_INVALID_CONFIG;
2662 goto end;
2663 }
2664
159b042f
JG
2665 switch (process_attr) {
2666 case LTTNG_PROCESS_ATTR_PROCESS_ID:
28ab034a
JG
2667 status =
2668 lttng_process_attr_process_id_tracker_handle_add_pid(
2669 tracker_handle, (pid_t) id);
159b042f
JG
2670 break;
2671 case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
28ab034a
JG
2672 status =
2673 lttng_process_attr_virtual_process_id_tracker_handle_add_pid(
2674 tracker_handle, (pid_t) id);
159b042f
JG
2675 break;
2676 case LTTNG_PROCESS_ATTR_USER_ID:
2677 status = lttng_process_attr_user_id_tracker_handle_add_uid(
28ab034a 2678 tracker_handle, (uid_t) id);
159b042f
JG
2679 break;
2680 case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
28ab034a
JG
2681 status =
2682 lttng_process_attr_virtual_user_id_tracker_handle_add_uid(
2683 tracker_handle, (uid_t) id);
159b042f
JG
2684 break;
2685 case LTTNG_PROCESS_ATTR_GROUP_ID:
2686 status = lttng_process_attr_group_id_tracker_handle_add_gid(
28ab034a 2687 tracker_handle, (gid_t) id);
159b042f
JG
2688 break;
2689 case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
28ab034a
JG
2690 status =
2691 lttng_process_attr_virtual_group_id_tracker_handle_add_gid(
2692 tracker_handle, (gid_t) id);
159b042f
JG
2693 break;
2694 default:
2695 ret = LTTNG_ERR_INVALID;
55c9e7ca
JR
2696 goto end;
2697 }
159b042f 2698 } else if (element_name &&
28ab034a 2699 !strcmp((const char *) node->name, element_name)) {
159b042f 2700 xmlChar *content = xmlNodeGetContent(node);
55c9e7ca 2701
55c9e7ca
JR
2702 if (!content) {
2703 ret = LTTNG_ERR_LOAD_INVALID_CONFIG;
2704 goto end;
2705 }
2d97a006 2706
159b042f
JG
2707 switch (process_attr) {
2708 case LTTNG_PROCESS_ATTR_USER_ID:
28ab034a
JG
2709 status =
2710 lttng_process_attr_user_id_tracker_handle_add_user_name(
2711 tracker_handle, (const char *) content);
159b042f
JG
2712 break;
2713 case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
28ab034a
JG
2714 status =
2715 lttng_process_attr_virtual_user_id_tracker_handle_add_user_name(
2716 tracker_handle, (const char *) content);
159b042f
JG
2717 break;
2718 case LTTNG_PROCESS_ATTR_GROUP_ID:
28ab034a
JG
2719 status =
2720 lttng_process_attr_group_id_tracker_handle_add_group_name(
2721 tracker_handle, (const char *) content);
159b042f
JG
2722 break;
2723 case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
28ab034a
JG
2724 status =
2725 lttng_process_attr_virtual_group_id_tracker_handle_add_group_name(
2726 tracker_handle, (const char *) content);
159b042f
JG
2727 break;
2728 default:
2729 free(content);
2730 ret = LTTNG_ERR_INVALID;
2d97a006
JR
2731 goto end;
2732 }
55c9e7ca 2733 free(content);
159b042f
JG
2734 }
2735 switch (status) {
2736 case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_OK:
2737 continue;
2738 case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_INVALID:
2739 ret = LTTNG_ERR_INVALID;
2740 break;
2741 case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_EXISTS:
2742 ret = LTTNG_ERR_PROCESS_ATTR_EXISTS;
2743 break;
2744 case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_MISSING:
2745 ret = LTTNG_ERR_PROCESS_ATTR_MISSING;
2746 break;
2747 case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_ERROR:
2748 case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_COMMUNICATION_ERROR:
2749 default:
2750 ret = LTTNG_ERR_UNK;
2751 goto end;
847a5916
JR
2752 }
2753 }
55c9e7ca 2754 node = id_target_node;
847a5916
JR
2755 }
2756
2757end:
159b042f 2758 lttng_process_attr_tracker_handle_destroy(tracker_handle);
847a5916
JR
2759 return ret;
2760}
2761
28ab034a 2762static int process_domain_node(xmlNodePtr domain_node, const char *session_name)
dcf266c0
JG
2763{
2764 int ret;
3afa94ae 2765 struct lttng_domain domain {};
cd9adb8b
JG
2766 struct lttng_handle *handle = nullptr;
2767 struct lttng_channel *channel = nullptr;
2768 xmlNodePtr channels_node = nullptr;
2769 xmlNodePtr trackers_node = nullptr;
2770 xmlNodePtr pid_tracker_node = nullptr;
2771 xmlNodePtr vpid_tracker_node = nullptr;
2772 xmlNodePtr uid_tracker_node = nullptr;
2773 xmlNodePtr vuid_tracker_node = nullptr;
2774 xmlNodePtr gid_tracker_node = nullptr;
2775 xmlNodePtr vgid_tracker_node = nullptr;
dcf266c0
JG
2776 xmlNodePtr node;
2777
a0377dfe 2778 LTTNG_ASSERT(session_name);
dcf266c0
JG
2779
2780 ret = init_domain(domain_node, &domain);
2781 if (ret) {
2782 goto end;
2783 }
2784
2785 handle = lttng_create_handle(session_name, &domain);
2786 if (!handle) {
2787 ret = -LTTNG_ERR_NOMEM;
2788 goto end;
2789 }
2790
2791 /* get the channels node */
28ab034a
JG
2792 for (node = xmlFirstElementChild(domain_node); node; node = xmlNextElementSibling(node)) {
2793 if (!strcmp((const char *) node->name, config_element_channels)) {
dcf266c0
JG
2794 channels_node = node;
2795 break;
2796 }
2797 }
2798
2799 if (!channels_node) {
2800 goto end;
2801 }
2802
2803 /* create all channels */
28ab034a 2804 for (node = xmlFirstElementChild(channels_node); node; node = xmlNextElementSibling(node)) {
36d1687c 2805 const enum lttng_domain_type original_domain = domain.type;
cd9adb8b
JG
2806 xmlNodePtr contexts_node = nullptr;
2807 xmlNodePtr events_node = nullptr;
dcf266c0
JG
2808 xmlNodePtr channel_attr_node;
2809
36d1687c
JG
2810 /*
2811 * Channels of the "agent" types cannot be created directly.
2812 * They are meant to be created implicitly through the
2813 * activation of events in their domain. However, a user
2814 * can override the default channel configuration attributes
2815 * by creating the underlying UST channel _before_ enabling
2816 * an agent domain event.
2817 *
2818 * Hence, the channel's type is substituted before the creation
2819 * and restored by the time the events are created.
2820 */
2821 switch (domain.type) {
2822 case LTTNG_DOMAIN_JUL:
2823 case LTTNG_DOMAIN_LOG4J:
2824 case LTTNG_DOMAIN_PYTHON:
2825 domain.type = LTTNG_DOMAIN_UST;
2826 default:
2827 break;
2828 }
2829
4fc2b126
JR
2830 channel = lttng_channel_create(&domain);
2831 if (!channel) {
2832 ret = -1;
2833 goto end;
2834 }
dcf266c0 2835
28ab034a
JG
2836 for (channel_attr_node = xmlFirstElementChild(node); channel_attr_node;
2837 channel_attr_node = xmlNextElementSibling(channel_attr_node)) {
2838 ret = process_channel_attr_node(
2839 channel_attr_node, channel, &contexts_node, &events_node);
dcf266c0
JG
2840 if (ret) {
2841 goto end;
2842 }
2843 }
2844
4fc2b126 2845 ret = lttng_enable_channel(handle, channel);
dcf266c0
JG
2846 if (ret < 0) {
2847 goto end;
2848 }
2849
36d1687c
JG
2850 /* Restore the original channel domain. */
2851 domain.type = original_domain;
2852
4fc2b126 2853 ret = process_events_node(events_node, handle, channel->name);
dcf266c0
JG
2854 if (ret) {
2855 goto end;
2856 }
2857
28ab034a 2858 ret = process_contexts_node(contexts_node, handle, channel->name);
dcf266c0
JG
2859 if (ret) {
2860 goto end;
2861 }
4fc2b126
JR
2862
2863 lttng_channel_destroy(channel);
dcf266c0 2864 }
cd9adb8b 2865 channel = nullptr;
847a5916
JR
2866
2867 /* get the trackers node */
28ab034a
JG
2868 for (node = xmlFirstElementChild(domain_node); node; node = xmlNextElementSibling(node)) {
2869 if (!strcmp((const char *) node->name, config_element_process_attr_trackers) ||
2870 !strcmp((const char *) node->name, config_element_trackers_legacy)) {
f7af9a72
JG
2871 if (trackers_node) {
2872 ERR("Only one instance of `%s` or `%s` is allowed in a session configuration",
28ab034a
JG
2873 config_element_process_attr_trackers,
2874 config_element_trackers_legacy);
f7af9a72
JG
2875 ret = -1;
2876 goto end;
2877 }
847a5916
JR
2878 trackers_node = node;
2879 break;
2880 }
2881 }
2882
2883 if (!trackers_node) {
2884 goto end;
2885 }
2886
28ab034a
JG
2887 for (node = xmlFirstElementChild(trackers_node); node; node = xmlNextElementSibling(node)) {
2888 if (!strcmp((const char *) node->name, config_element_process_attr_tracker_pid)) {
847a5916 2889 pid_tracker_node = node;
28ab034a
JG
2890 ret = process_id_tracker_node(
2891 pid_tracker_node, handle, LTTNG_PROCESS_ATTR_PROCESS_ID);
55c9e7ca
JR
2892 if (ret) {
2893 goto end;
2894 }
2895 }
28ab034a 2896 if (!strcmp((const char *) node->name, config_element_process_attr_tracker_vpid)) {
55c9e7ca 2897 vpid_tracker_node = node;
28ab034a
JG
2898 ret = process_id_tracker_node(
2899 vpid_tracker_node, handle, LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID);
55c9e7ca
JR
2900 if (ret) {
2901 goto end;
2902 }
2903 }
28ab034a 2904 if (!strcmp((const char *) node->name, config_element_process_attr_tracker_uid)) {
55c9e7ca 2905 uid_tracker_node = node;
28ab034a
JG
2906 ret = process_id_tracker_node(
2907 uid_tracker_node, handle, LTTNG_PROCESS_ATTR_USER_ID);
55c9e7ca
JR
2908 if (ret) {
2909 goto end;
2910 }
2911 }
28ab034a 2912 if (!strcmp((const char *) node->name, config_element_process_attr_tracker_vuid)) {
55c9e7ca 2913 vuid_tracker_node = node;
28ab034a
JG
2914 ret = process_id_tracker_node(
2915 vuid_tracker_node, handle, LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID);
55c9e7ca
JR
2916 if (ret) {
2917 goto end;
2918 }
2919 }
28ab034a 2920 if (!strcmp((const char *) node->name, config_element_process_attr_tracker_gid)) {
55c9e7ca 2921 gid_tracker_node = node;
28ab034a
JG
2922 ret = process_id_tracker_node(
2923 gid_tracker_node, handle, LTTNG_PROCESS_ATTR_GROUP_ID);
55c9e7ca
JR
2924 if (ret) {
2925 goto end;
2926 }
2927 }
28ab034a 2928 if (!strcmp((const char *) node->name, config_element_process_attr_tracker_vgid)) {
55c9e7ca 2929 vgid_tracker_node = node;
28ab034a
JG
2930 ret = process_id_tracker_node(
2931 vgid_tracker_node, handle, LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID);
847a5916
JR
2932 if (ret) {
2933 goto end;
2934 }
2935 }
28ab034a 2936 if (!strcmp((const char *) node->name, config_element_pid_tracker_legacy)) {
f7af9a72
JG
2937 ret = process_legacy_pid_tracker_node(node, handle);
2938 if (ret) {
2939 goto end;
2940 }
2941 }
847a5916
JR
2942 }
2943
dcf266c0 2944end:
4fc2b126 2945 lttng_channel_destroy(channel);
dcf266c0
JG
2946 lttng_destroy_handle(handle);
2947 return ret;
2948}
2949
28ab034a 2950static int add_periodic_rotation(const char *name, uint64_t time_us)
66ea93b1
JG
2951{
2952 int ret;
2953 enum lttng_rotation_status status;
28ab034a 2954 struct lttng_rotation_schedule *periodic = lttng_rotation_schedule_periodic_create();
66ea93b1
JG
2955
2956 if (!periodic) {
2957 ret = -LTTNG_ERR_NOMEM;
2958 goto error;
2959 }
2960
28ab034a 2961 status = lttng_rotation_schedule_periodic_set_period(periodic, time_us);
66ea93b1
JG
2962 if (status != LTTNG_ROTATION_STATUS_OK) {
2963 ret = -LTTNG_ERR_INVALID;
2964 goto error;
2965 }
2966
2967 status = lttng_session_add_rotation_schedule(name, periodic);
2968 switch (status) {
2969 case LTTNG_ROTATION_STATUS_OK:
ce6176f2 2970 ret = 0;
66ea93b1
JG
2971 break;
2972 case LTTNG_ROTATION_STATUS_SCHEDULE_ALREADY_SET:
2973 case LTTNG_ROTATION_STATUS_INVALID:
2974 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
2975 break;
2976 default:
2977 ret = -LTTNG_ERR_UNK;
2978 break;
2979 }
2980error:
2981 lttng_rotation_schedule_destroy(periodic);
2982 return ret;
2983}
2984
28ab034a 2985static int add_size_rotation(const char *name, uint64_t size_bytes)
66ea93b1
JG
2986{
2987 int ret;
2988 enum lttng_rotation_status status;
28ab034a 2989 struct lttng_rotation_schedule *size = lttng_rotation_schedule_size_threshold_create();
66ea93b1
JG
2990
2991 if (!size) {
2992 ret = -LTTNG_ERR_NOMEM;
2993 goto error;
2994 }
2995
28ab034a 2996 status = lttng_rotation_schedule_size_threshold_set_threshold(size, size_bytes);
66ea93b1
JG
2997 if (status != LTTNG_ROTATION_STATUS_OK) {
2998 ret = -LTTNG_ERR_INVALID;
2999 goto error;
3000 }
3001
3002 status = lttng_session_add_rotation_schedule(name, size);
3003 switch (status) {
3004 case LTTNG_ROTATION_STATUS_OK:
ce6176f2 3005 ret = 0;
66ea93b1
JG
3006 break;
3007 case LTTNG_ROTATION_STATUS_SCHEDULE_ALREADY_SET:
3008 case LTTNG_ROTATION_STATUS_INVALID:
3009 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
3010 break;
3011 default:
3012 ret = -LTTNG_ERR_UNK;
3013 break;
3014 }
3015error:
3016 lttng_rotation_schedule_destroy(size);
3017 return ret;
3018}
3019
28ab034a
JG
3020static int process_session_rotation_schedules_node(xmlNodePtr schedules_node,
3021 uint64_t *rotation_timer_interval,
3022 uint64_t *rotation_size)
ce6176f2
JG
3023{
3024 int ret = 0;
3025 xmlNodePtr child;
3026
28ab034a
JG
3027 for (child = xmlFirstElementChild(schedules_node); child;
3028 child = xmlNextElementSibling(child)) {
ce6176f2 3029 if (!strcmp((const char *) child->name,
28ab034a 3030 config_element_rotation_schedule_periodic)) {
ce6176f2
JG
3031 xmlChar *content;
3032 xmlNodePtr time_us_node;
3033
3034 /* periodic rotation schedule */
3035 time_us_node = xmlFirstElementChild(child);
3036 if (!time_us_node ||
28ab034a
JG
3037 strcmp((const char *) time_us_node->name,
3038 config_element_rotation_schedule_periodic_time_us)) {
ce6176f2
JG
3039 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
3040 goto end;
3041 }
3042
3043 /* time_us child */
3044 content = xmlNodeGetContent(time_us_node);
3045 if (!content) {
3046 ret = -LTTNG_ERR_NOMEM;
3047 goto end;
3048 }
3049 ret = parse_uint(content, rotation_timer_interval);
3050 free(content);
3051 if (ret) {
3052 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
3053 goto end;
3054 }
3055 } else if (!strcmp((const char *) child->name,
28ab034a 3056 config_element_rotation_schedule_size_threshold)) {
ce6176f2
JG
3057 xmlChar *content;
3058 xmlNodePtr bytes_node;
3059
3060 /* size_threshold rotation schedule */
3061 bytes_node = xmlFirstElementChild(child);
3062 if (!bytes_node ||
28ab034a
JG
3063 strcmp((const char *) bytes_node->name,
3064 config_element_rotation_schedule_size_threshold_bytes)) {
ce6176f2
JG
3065 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
3066 goto end;
3067 }
3068
3069 /* bytes child */
3070 content = xmlNodeGetContent(bytes_node);
3071 if (!content) {
3072 ret = -LTTNG_ERR_NOMEM;
3073 goto end;
3074 }
3075 ret = parse_uint(content, rotation_size);
3076 free(content);
3077 if (ret) {
3078 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
3079 goto end;
3080 }
3081 }
3082 }
3083
3084end:
3085 return ret;
3086}
3087
28ab034a
JG
3088static int process_session_node(xmlNodePtr session_node,
3089 const char *session_name,
3090 int overwrite,
3091 const struct config_load_session_override_attr *overrides)
dcf266c0
JG
3092{
3093 int ret, started = -1, snapshot_mode = -1;
28ab034a 3094 uint64_t live_timer_interval = UINT64_MAX, rotation_timer_interval = 0, rotation_size = 0;
cd9adb8b
JG
3095 xmlChar *name = nullptr;
3096 xmlChar *shm_path = nullptr;
3097 xmlNodePtr domains_node = nullptr;
3098 xmlNodePtr output_node = nullptr;
dcf266c0 3099 xmlNodePtr node;
90936dcf 3100 xmlNodePtr attributes_child;
cd9adb8b
JG
3101 struct lttng_domain *kernel_domain = nullptr;
3102 struct lttng_domain *ust_domain = nullptr;
3103 struct lttng_domain *jul_domain = nullptr;
3104 struct lttng_domain *log4j_domain = nullptr;
3105 struct lttng_domain *python_domain = nullptr;
dcf266c0 3106
28ab034a
JG
3107 for (node = xmlFirstElementChild(session_node); node; node = xmlNextElementSibling(node)) {
3108 if (!name && !strcmp((const char *) node->name, config_element_name)) {
dcf266c0
JG
3109 /* name */
3110 xmlChar *node_content = xmlNodeGetContent(node);
3111 if (!node_content) {
3112 ret = -LTTNG_ERR_NOMEM;
c2da8cde 3113 goto error;
dcf266c0
JG
3114 }
3115
d324faf7 3116 name = node_content;
28ab034a
JG
3117 } else if (!domains_node &&
3118 !strcmp((const char *) node->name, config_element_domains)) {
dcf266c0
JG
3119 /* domains */
3120 domains_node = node;
28ab034a
JG
3121 } else if (started == -1 &&
3122 !strcmp((const char *) node->name, config_element_started)) {
dcf266c0
JG
3123 /* started */
3124 xmlChar *node_content = xmlNodeGetContent(node);
3125 if (!node_content) {
3126 ret = -LTTNG_ERR_NOMEM;
c2da8cde 3127 goto error;
dcf266c0
JG
3128 }
3129
3130 ret = parse_bool(node_content, &started);
3131 free(node_content);
3132 if (ret) {
3133 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
c2da8cde 3134 goto error;
dcf266c0 3135 }
28ab034a
JG
3136 } else if (!output_node &&
3137 !strcmp((const char *) node->name, config_element_output)) {
dcf266c0
JG
3138 /* output */
3139 output_node = node;
28ab034a
JG
3140 } else if (!shm_path &&
3141 !strcmp((const char *) node->name, config_element_shared_memory_path)) {
9e7c9f56
JR
3142 /* shared memory path */
3143 xmlChar *node_content = xmlNodeGetContent(node);
3144 if (!node_content) {
3145 ret = -LTTNG_ERR_NOMEM;
3146 goto error;
3147 }
3148
3149 shm_path = node_content;
dcf266c0 3150 } else {
259c2674
JD
3151 /*
3152 * attributes, snapshot_mode, live_timer_interval, rotation_size,
90936dcf
JD
3153 * rotation_timer_interval.
3154 */
3155 for (attributes_child = xmlFirstElementChild(node); attributes_child;
28ab034a 3156 attributes_child = xmlNextElementSibling(attributes_child)) {
90936dcf 3157 if (!strcmp((const char *) attributes_child->name,
28ab034a 3158 config_element_snapshot_mode)) {
90936dcf
JD
3159 /* snapshot_mode */
3160 xmlChar *snapshot_mode_content =
3161 xmlNodeGetContent(attributes_child);
3162 if (!snapshot_mode_content) {
3163 ret = -LTTNG_ERR_NOMEM;
3164 goto error;
3165 }
dcf266c0 3166
90936dcf
JD
3167 ret = parse_bool(snapshot_mode_content, &snapshot_mode);
3168 free(snapshot_mode_content);
3169 if (ret) {
3170 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
3171 goto error;
3172 }
3173 } else if (!strcmp((const char *) attributes_child->name,
28ab034a 3174 config_element_live_timer_interval)) {
90936dcf
JD
3175 /* live_timer_interval */
3176 xmlChar *timer_interval_content =
3177 xmlNodeGetContent(attributes_child);
3178 if (!timer_interval_content) {
3179 ret = -LTTNG_ERR_NOMEM;
3180 goto error;
3181 }
dcf266c0 3182
28ab034a
JG
3183 ret = parse_uint(timer_interval_content,
3184 &live_timer_interval);
90936dcf
JD
3185 free(timer_interval_content);
3186 if (ret) {
3187 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
3188 goto error;
3189 }
ce6176f2 3190 } else if (!strcmp((const char *) attributes_child->name,
28ab034a 3191 config_element_rotation_schedules)) {
ce6176f2 3192 ret = process_session_rotation_schedules_node(
28ab034a
JG
3193 attributes_child,
3194 &rotation_timer_interval,
3195 &rotation_size);
90936dcf
JD
3196 if (ret) {
3197 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
3198 goto error;
3199 }
259c2674
JD
3200 }
3201 }
dcf266c0
JG
3202 }
3203 }
3204
3205 if (!name) {
3206 /* Mandatory attribute, as defined in the session XSD */
3207 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
c2da8cde 3208 goto error;
dcf266c0
JG
3209 }
3210
d324faf7 3211 if (session_name && strcmp((char *) name, session_name)) {
dcf266c0 3212 /* This is not the session we are looking for */
c2da8cde
DG
3213 ret = -LTTNG_ERR_NO_SESSION;
3214 goto error;
dcf266c0
JG
3215 }
3216
3217 /* Init domains to create the session handles */
28ab034a 3218 for (node = xmlFirstElementChild(domains_node); node; node = xmlNextElementSibling(node)) {
64803277 3219 lttng_domain *domain = zmalloc<lttng_domain>();
dcf266c0 3220
dcf266c0
JG
3221 if (!domain) {
3222 ret = -LTTNG_ERR_NOMEM;
c2da8cde 3223 goto error;
dcf266c0
JG
3224 }
3225
3226 ret = init_domain(node, domain);
3227 if (ret) {
3228 goto domain_init_error;
3229 }
3230
3231 switch (domain->type) {
3232 case LTTNG_DOMAIN_KERNEL:
c33e6729
DG
3233 if (kernel_domain) {
3234 /* Same domain seen twice, invalid! */
3235 goto domain_init_error;
3236 }
dcf266c0
JG
3237 kernel_domain = domain;
3238 break;
3239 case LTTNG_DOMAIN_UST:
c33e6729
DG
3240 if (ust_domain) {
3241 /* Same domain seen twice, invalid! */
3242 goto domain_init_error;
3243 }
dcf266c0
JG
3244 ust_domain = domain;
3245 break;
3246 case LTTNG_DOMAIN_JUL:
c33e6729
DG
3247 if (jul_domain) {
3248 /* Same domain seen twice, invalid! */
3249 goto domain_init_error;
3250 }
dcf266c0
JG
3251 jul_domain = domain;
3252 break;
5cdb6027
DG
3253 case LTTNG_DOMAIN_LOG4J:
3254 if (log4j_domain) {
3255 /* Same domain seen twice, invalid! */
3256 goto domain_init_error;
3257 }
3258 log4j_domain = domain;
3259 break;
0e115563
DG
3260 case LTTNG_DOMAIN_PYTHON:
3261 if (python_domain) {
3262 /* Same domain seen twice, invalid! */
3263 goto domain_init_error;
3264 }
3265 python_domain = domain;
3266 break;
dcf266c0
JG
3267 default:
3268 WARN("Invalid domain type");
3269 goto domain_init_error;
3270 }
3271 continue;
28ab034a 3272 domain_init_error:
dcf266c0
JG
3273 free(domain);
3274 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
c2da8cde 3275 goto error;
dcf266c0
JG
3276 }
3277
2aaf5fc7
JR
3278 /* Apply overrides */
3279 if (overrides) {
3280 if (overrides->session_name) {
3281 xmlChar *name_override = xmlStrdup(BAD_CAST(overrides->session_name));
3282 if (!name_override) {
3283 ret = -LTTNG_ERR_NOMEM;
3284 goto error;
3285 }
3286
3287 /* Overrides the session name to the provided name */
3288 xmlFree(name);
3289 name = name_override;
3290 }
3291 }
3292
40b4155f 3293 if (overwrite) {
dcf266c0 3294 /* Destroy session if it exists */
d324faf7 3295 ret = lttng_destroy_session((const char *) name);
dcf266c0
JG
3296 if (ret && ret != -LTTNG_ERR_SESS_NOT_FOUND) {
3297 ERR("Failed to destroy existing session.");
c2da8cde 3298 goto error;
dcf266c0
JG
3299 }
3300 }
3301
3302 /* Create session type depending on output type */
3303 if (snapshot_mode && snapshot_mode != -1) {
28ab034a
JG
3304 ret = create_snapshot_session((const char *) name, output_node, overrides);
3305 } else if (live_timer_interval && live_timer_interval != UINT64_MAX) {
3306 ret = create_session(
3307 (const char *) name, output_node, live_timer_interval, overrides);
dcf266c0
JG
3308 } else {
3309 /* regular session */
28ab034a 3310 ret = create_session((const char *) name, output_node, UINT64_MAX, overrides);
dcf266c0 3311 }
dcf266c0 3312 if (ret) {
c2da8cde 3313 goto error;
dcf266c0
JG
3314 }
3315
9e7c9f56 3316 if (shm_path) {
28ab034a 3317 ret = lttng_set_session_shm_path((const char *) name, (const char *) shm_path);
9e7c9f56
JR
3318 if (ret) {
3319 goto error;
3320 }
3321 }
3322
28ab034a 3323 for (node = xmlFirstElementChild(domains_node); node; node = xmlNextElementSibling(node)) {
d324faf7 3324 ret = process_domain_node(node, (const char *) name);
dcf266c0
JG
3325 if (ret) {
3326 goto end;
3327 }
3328 }
3329
66ea93b1 3330 if (rotation_timer_interval) {
28ab034a 3331 ret = add_periodic_rotation((const char *) name, rotation_timer_interval);
66ea93b1 3332 if (ret < 0) {
259c2674
JD
3333 goto error;
3334 }
66ea93b1
JG
3335 }
3336 if (rotation_size) {
28ab034a 3337 ret = add_size_rotation((const char *) name, rotation_size);
66ea93b1 3338 if (ret < 0) {
259c2674
JD
3339 goto error;
3340 }
3341 }
3342
dcf266c0 3343 if (started) {
d324faf7 3344 ret = lttng_start_tracing((const char *) name);
dcf266c0
JG
3345 if (ret) {
3346 goto end;
3347 }
3348 }
c2da8cde 3349
dcf266c0 3350end:
b2579dc1 3351 if (ret < 0) {
28ab034a 3352 ERR("Failed to load session %s: %s", (const char *) name, lttng_strerror(ret));
d324faf7 3353 lttng_destroy_session((const char *) name);
b2579dc1
JG
3354 }
3355
c2da8cde 3356error:
dcf266c0
JG
3357 free(kernel_domain);
3358 free(ust_domain);
3359 free(jul_domain);
5cdb6027 3360 free(log4j_domain);
135a3893 3361 free(python_domain);
d324faf7 3362 xmlFree(name);
9e7c9f56 3363 xmlFree(shm_path);
dcf266c0
JG
3364 return ret;
3365}
3366
cf53c06d
DG
3367/*
3368 * Return 1 if the given path is readable by the current UID or 0 if not.
3369 * Return -1 if the path is EPERM.
3370 */
3371static int validate_file_read_creds(const char *path)
3372{
3373 int ret;
3374
a0377dfe 3375 LTTNG_ASSERT(path);
cf53c06d
DG
3376
3377 /* Can we read the file. */
3378 ret = access(path, R_OK);
3379 if (!ret) {
3380 goto valid;
3381 }
3382 if (errno == EACCES) {
3383 return -1;
3384 } else {
3385 /* Invalid. */
3386 return 0;
3387 }
3388valid:
3389 return 1;
3390}
3391
28ab034a
JG
3392static int load_session_from_file(const char *path,
3393 const char *session_name,
3394 struct session_config_validation_ctx *validation_ctx,
3395 int overwrite,
3396 const struct config_load_session_override_attr *overrides)
dcf266c0
JG
3397{
3398 int ret, session_found = !session_name;
cd9adb8b 3399 xmlDocPtr doc = nullptr;
dcf266c0
JG
3400 xmlNodePtr sessions_node;
3401 xmlNodePtr session_node;
dcf266c0 3402
a0377dfe
FD
3403 LTTNG_ASSERT(path);
3404 LTTNG_ASSERT(validation_ctx);
dcf266c0 3405
cf53c06d
DG
3406 ret = validate_file_read_creds(path);
3407 if (ret != 1) {
3408 if (ret == -1) {
3409 ret = -LTTNG_ERR_EPERM;
3410 } else {
3411 ret = -LTTNG_ERR_LOAD_SESSION_NOENT;
3412 }
dcf266c0
JG
3413 goto end;
3414 }
3415
3416 doc = xmlParseFile(path);
3417 if (!doc) {
3418 ret = -LTTNG_ERR_LOAD_IO_FAIL;
3419 goto end;
3420 }
3421
3422 ret = xmlSchemaValidateDoc(validation_ctx->schema_validation_ctx, doc);
3423 if (ret) {
3424 ERR("Session configuration file validation failed");
3425 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
3426 goto end;
3427 }
3428
3429 sessions_node = xmlDocGetRootElement(doc);
3430 if (!sessions_node) {
55c9e7ca 3431 ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
dcf266c0
JG
3432 goto end;
3433 }
3434
28ab034a
JG
3435 for (session_node = xmlFirstElementChild(sessions_node); session_node;
3436 session_node = xmlNextElementSibling(session_node)) {
3437 ret = process_session_node(session_node, session_name, overwrite, overrides);
317ea246
JG
3438 if (!session_name && ret) {
3439 /* Loading error occurred. */
3440 goto end;
3441 } else if (session_name) {
3442 if (ret == 0) {
3443 /* Target session found and loaded */
3444 session_found = 1;
3445 break;
3446 } else if (ret == -LTTNG_ERR_NO_SESSION) {
3447 /*
3448 * Ignore this error, we are looking for a
3449 * specific session.
3450 */
3451 ret = 0;
3452 } else {
3453 /* Loading error occurred. */
3454 goto end;
3455 }
dcf266c0
JG
3456 }
3457 }
3458end:
3459 xmlFreeDoc(doc);
3460 if (!ret) {
a96bc65d 3461 ret = session_found ? 0 : -LTTNG_ERR_LOAD_SESSION_NOENT;
dcf266c0
JG
3462 }
3463 return ret;
3464}
3465
28ab034a
JG
3466static int load_session_from_path(const char *path,
3467 const char *session_name,
3468 struct session_config_validation_ctx *validation_ctx,
3469 int overwrite,
3470 const struct config_load_session_override_attr *overrides)
dcf266c0
JG
3471{
3472 int ret, session_found = !session_name;
cd9adb8b 3473 DIR *directory = nullptr;
cce35f91
JG
3474 struct lttng_dynamic_buffer file_path;
3475 size_t path_len;
dcf266c0 3476
a0377dfe
FD
3477 LTTNG_ASSERT(path);
3478 LTTNG_ASSERT(validation_ctx);
cce35f91
JG
3479 path_len = strlen(path);
3480 lttng_dynamic_buffer_init(&file_path);
3481 if (path_len >= LTTNG_PATH_MAX) {
3482 ERR("Session configuration load path \"%s\" length (%zu) exceeds the maximal length allowed (%d)",
28ab034a
JG
3483 path,
3484 path_len,
3485 LTTNG_PATH_MAX);
cce35f91
JG
3486 ret = -LTTNG_ERR_INVALID;
3487 goto end;
3488 }
dcf266c0 3489
4af16958
DG
3490 directory = opendir(path);
3491 if (!directory) {
11143783
DG
3492 switch (errno) {
3493 case ENOTDIR:
0f0a81b5
DG
3494 /* Try the file loading. */
3495 break;
11143783
DG
3496 case ENOENT:
3497 ret = -LTTNG_ERR_LOAD_SESSION_NOENT;
3498 goto end;
3499 default:
0f0a81b5
DG
3500 ret = -LTTNG_ERR_LOAD_IO_FAIL;
3501 goto end;
4af16958 3502 }
dcf266c0 3503 }
4af16958 3504 if (directory) {
cce35f91 3505 size_t file_path_root_len;
dcf266c0 3506
28ab034a 3507 ret = lttng_dynamic_buffer_set_capacity(&file_path, LTTNG_PATH_MAX);
cce35f91
JG
3508 if (ret) {
3509 ret = -LTTNG_ERR_NOMEM;
dcf266c0
JG
3510 goto end;
3511 }
3512
28ab034a 3513 ret = lttng_dynamic_buffer_append(&file_path, path, path_len);
cce35f91 3514 if (ret) {
dcf266c0 3515 ret = -LTTNG_ERR_NOMEM;
dcf266c0
JG
3516 goto end;
3517 }
3518
cce35f91 3519 if (file_path.data[file_path.size - 1] != '/') {
28ab034a 3520 ret = lttng_dynamic_buffer_append(&file_path, "/", 1);
cce35f91
JG
3521 if (ret) {
3522 ret = -LTTNG_ERR_NOMEM;
3523 goto end;
3524 }
dcf266c0 3525 }
cce35f91 3526 file_path_root_len = file_path.size;
dcf266c0
JG
3527
3528 /* Search for *.lttng files */
9a2df626
MJ
3529 for (;;) {
3530 size_t file_name_len;
3531 struct dirent *result;
3532
3533 /*
3534 * When the end of the directory stream is reached, NULL
3535 * is returned and errno is kept unchanged. When an
3536 * error occurs, NULL is returned and errno is set
3537 * accordingly. To distinguish between the two, set
3538 * errno to zero before calling readdir().
3539 *
3540 * On success, readdir() returns a pointer to a dirent
3541 * structure. This structure may be statically
3542 * allocated, do not attempt to free(3) it.
3543 */
3544 errno = 0;
3545 result = readdir(directory);
3546
ff86d8d0 3547 /* Reached end of dir stream or error out. */
9a2df626
MJ
3548 if (!result) {
3549 if (errno) {
28ab034a
JG
3550 PERROR("Failed to enumerate the contents of path \"%s\" while loading session, readdir returned",
3551 path);
9a2df626
MJ
3552 ret = -LTTNG_ERR_LOAD_IO_FAIL;
3553 goto end;
3554 }
3555 break;
3556 }
3557
3558 file_name_len = strlen(result->d_name);
dcf266c0 3559
28ab034a 3560 if (file_name_len <= sizeof(DEFAULT_SESSION_CONFIG_FILE_EXTENSION)) {
dcf266c0
JG
3561 continue;
3562 }
3563
cce35f91
JG
3564 if (file_path.size + file_name_len >= LTTNG_PATH_MAX) {
3565 WARN("Ignoring file \"%s\" since the path's length (%zu) would exceed the maximal permitted size (%d)",
28ab034a
JG
3566 result->d_name,
3567 /* +1 to account for NULL terminator. */
3568 file_path.size + file_name_len + 1,
3569 LTTNG_PATH_MAX);
dcf266c0
JG
3570 continue;
3571 }
3572
cce35f91 3573 /* Does the file end with .lttng? */
dcf266c0 3574 if (strcmp(DEFAULT_SESSION_CONFIG_FILE_EXTENSION,
28ab034a
JG
3575 result->d_name + file_name_len -
3576 sizeof(DEFAULT_SESSION_CONFIG_FILE_EXTENSION) + 1)) {
dcf266c0
JG
3577 continue;
3578 }
3579
28ab034a
JG
3580 ret = lttng_dynamic_buffer_append(
3581 &file_path, result->d_name, file_name_len + 1);
cce35f91
JG
3582 if (ret) {
3583 ret = -LTTNG_ERR_NOMEM;
3584 goto end;
3585 }
dcf266c0 3586
28ab034a
JG
3587 ret = load_session_from_file(
3588 file_path.data, session_name, validation_ctx, overwrite, overrides);
3589 if (session_name && (!ret || ret != -LTTNG_ERR_LOAD_SESSION_NOENT)) {
dcf266c0
JG
3590 session_found = 1;
3591 break;
3592 }
55c9e7ca
JR
3593 if (ret && ret != -LTTNG_ERR_LOAD_SESSION_NOENT) {
3594 goto end;
3595 }
cce35f91
JG
3596 /*
3597 * Reset the buffer's size to the location of the
3598 * path's trailing '/'.
3599 */
28ab034a 3600 ret = lttng_dynamic_buffer_set_size(&file_path, file_path_root_len);
cce35f91
JG
3601 if (ret) {
3602 ret = -LTTNG_ERR_UNK;
3603 goto end;
3604 }
dcf266c0 3605 }
dcf266c0 3606 } else {
28ab034a
JG
3607 ret = load_session_from_file(
3608 path, session_name, validation_ctx, overwrite, overrides);
dcf266c0
JG
3609 if (ret) {
3610 goto end;
dcf266c0 3611 }
55c9e7ca 3612 session_found = 1;
dcf266c0
JG
3613 }
3614
55c9e7ca 3615 ret = 0;
dcf266c0
JG
3616end:
3617 if (directory) {
3618 if (closedir(directory)) {
3619 PERROR("closedir");
3620 }
3621 }
55c9e7ca
JR
3622 if (!ret && !session_found) {
3623 ret = -LTTNG_ERR_LOAD_SESSION_NOENT;
dcf266c0 3624 }
cce35f91 3625 lttng_dynamic_buffer_reset(&file_path);
dcf266c0
JG
3626 return ret;
3627}
3628
ab38c13f
DG
3629/*
3630 * Validate that the given path's credentials and the current process have the
cf53c06d 3631 * same UID. If so, return 1 else return 0 if it does NOT match.
ab38c13f
DG
3632 */
3633static int validate_path_creds(const char *path)
3634{
3635 int ret, uid = getuid();
3636 struct stat buf;
3637
a0377dfe 3638 LTTNG_ASSERT(path);
ab38c13f 3639
cf53c06d 3640 if (uid == 0) {
ab38c13f
DG
3641 goto valid;
3642 }
3643
3644 ret = stat(path, &buf);
3645 if (ret < 0) {
3646 if (errno != ENOENT) {
3647 PERROR("stat");
3648 }
ab38c13f
DG
3649 goto valid;
3650 }
3651
3652 if (buf.st_uid != uid) {
3653 goto invalid;
3654 }
3655
3656valid:
ab38c13f 3657 return 1;
cf53c06d
DG
3658invalid:
3659 return 0;
ab38c13f
DG
3660}
3661
28ab034a
JG
3662int config_load_session(const char *path,
3663 const char *session_name,
3664 int overwrite,
3665 unsigned int autoload,
3666 const struct config_load_session_override_attr *overrides)
dcf266c0
JG
3667{
3668 int ret;
6c66fa0f 3669 bool session_loaded = false;
cd9adb8b 3670 const char *path_ptr = nullptr;
1c9a0b0e 3671 struct session_config_validation_ctx validation_ctx = {};
dcf266c0
JG
3672
3673 ret = init_session_config_validation_ctx(&validation_ctx);
3674 if (ret) {
3675 goto end;
3676 }
3677
3678 if (!path) {
4f00620d 3679 const char *home_path;
ab38c13f
DG
3680 const char *sys_path;
3681
dcf266c0 3682 /* Try home path */
ab38c13f 3683 home_path = utils_get_home_dir();
dcf266c0 3684 if (home_path) {
db8196db 3685 char path_buf[PATH_MAX];
dcf266c0 3686
d4fcf703
DG
3687 /*
3688 * Try user session configuration path. Ignore error here so we can
3689 * continue loading the system wide sessions.
3690 */
ab38c13f 3691 if (autoload) {
28ab034a
JG
3692 ret = snprintf(path_buf,
3693 sizeof(path_buf),
3694 DEFAULT_SESSION_HOME_CONFIGPATH
3695 "/" DEFAULT_SESSION_CONFIG_AUTOLOAD,
3696 home_path);
cf53c06d
DG
3697 if (ret < 0) {
3698 PERROR("snprintf session autoload home config path");
55c9e7ca 3699 ret = -LTTNG_ERR_INVALID;
cf53c06d
DG
3700 goto end;
3701 }
3702
3703 /*
3704 * Credentials are only validated for the autoload in order to
3705 * avoid any user session daemon to try to load kernel sessions
3706 * automatically and failing all the times.
3707 */
db8196db 3708 ret = validate_path_creds(path_buf);
cf53c06d 3709 if (ret) {
db8196db 3710 path_ptr = path_buf;
cf53c06d 3711 }
ab38c13f 3712 } else {
28ab034a
JG
3713 ret = snprintf(path_buf,
3714 sizeof(path_buf),
3715 DEFAULT_SESSION_HOME_CONFIGPATH,
3716 home_path);
cf53c06d
DG
3717 if (ret < 0) {
3718 PERROR("snprintf session home config path");
55c9e7ca 3719 ret = -LTTNG_ERR_INVALID;
cf53c06d
DG
3720 goto end;
3721 }
db8196db 3722 path_ptr = path_buf;
ab38c13f 3723 }
cf53c06d 3724 if (path_ptr) {
28ab034a
JG
3725 ret = load_session_from_path(path_ptr,
3726 session_name,
3727 &validation_ctx,
3728 overwrite,
3729 overrides);
d4fcf703
DG
3730 if (ret && ret != -LTTNG_ERR_LOAD_SESSION_NOENT) {
3731 goto end;
3732 }
3733 /*
3734 * Continue even if the session was found since we have to try
3735 * the system wide sessions.
3736 */
6c66fa0f 3737 session_loaded = true;
ab38c13f 3738 }
d4fcf703 3739 }
ab38c13f 3740
cf53c06d 3741 /* Reset path pointer for the system wide dir. */
cd9adb8b 3742 path_ptr = nullptr;
cf53c06d 3743
d4fcf703
DG
3744 /* Try system wide configuration directory. */
3745 if (autoload) {
28ab034a
JG
3746 sys_path = DEFAULT_SESSION_SYSTEM_CONFIGPATH
3747 "/" DEFAULT_SESSION_CONFIG_AUTOLOAD;
cf53c06d
DG
3748 ret = validate_path_creds(sys_path);
3749 if (ret) {
3750 path_ptr = sys_path;
3751 }
d4fcf703 3752 } else {
cf53c06d
DG
3753 sys_path = DEFAULT_SESSION_SYSTEM_CONFIGPATH;
3754 path_ptr = sys_path;
d4fcf703
DG
3755 }
3756
cf53c06d 3757 if (path_ptr) {
28ab034a
JG
3758 ret = load_session_from_path(
3759 path_ptr, session_name, &validation_ctx, overwrite, overrides);
6c66fa0f
JG
3760 if (!ret) {
3761 session_loaded = true;
3762 }
55c9e7ca
JR
3763 } else {
3764 ret = 0;
dcf266c0
JG
3765 }
3766 } else {
3767 ret = access(path, F_OK);
3768 if (ret < 0) {
3769 PERROR("access");
3770 switch (errno) {
3771 case ENOENT:
3772 ret = -LTTNG_ERR_INVALID;
3773 WARN("Session configuration path does not exist.");
3774 break;
3775 case EACCES:
3776 ret = -LTTNG_ERR_EPERM;
3777 break;
3778 default:
3779 ret = -LTTNG_ERR_UNK;
3780 break;
3781 }
3782 goto end;
3783 }
3784
28ab034a
JG
3785 ret = load_session_from_path(
3786 path, session_name, &validation_ctx, overwrite, overrides);
dcf266c0
JG
3787 }
3788end:
3789 fini_session_config_validation_ctx(&validation_ctx);
d2b6efff
JG
3790 if (ret == -LTTNG_ERR_LOAD_SESSION_NOENT && !session_name && !path) {
3791 /*
3792 * Don't report an error if no sessions are found when called
3793 * without a session_name or a search path.
3794 */
3795 ret = 0;
3796 }
6c66fa0f
JG
3797
3798 if (session_loaded && ret == -LTTNG_ERR_LOAD_SESSION_NOENT) {
3799 /* A matching session was found in one of the search paths. */
3800 ret = 0;
3801 }
dcf266c0
JG
3802 return ret;
3803}
56766c75 3804
cd9adb8b 3805static void __attribute__((destructor)) session_config_exit()
56766c75
JG
3806{
3807 xmlCleanupParser();
3808}
This page took 0.262299 seconds and 4 git commands to generate.