sessiond: agent: enable events matching event notifiers
[lttng-tools.git] / src / common / event-rule / tracepoint.c
CommitLineData
6d420eff
JR
1/*
2 * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8#include <assert.h>
58daac01 9#include <common/credentials.h>
6d420eff
JR
10#include <common/error.h>
11#include <common/macros.h>
12#include <common/payload.h>
13#include <common/payload-view.h>
14#include <common/runas.h>
959e3c66
JR
15#include <common/hashtable/hashtable.h>
16#include <common/hashtable/utils.h>
6d420eff
JR
17#include <lttng/event-rule/event-rule-internal.h>
18#include <lttng/event-rule/tracepoint-internal.h>
44760c20 19#include <lttng/event.h>
6d420eff
JR
20
21#define IS_TRACEPOINT_EVENT_RULE(rule) \
22 (lttng_event_rule_get_type(rule) == LTTNG_EVENT_RULE_TYPE_TRACEPOINT)
23
24static void lttng_event_rule_tracepoint_destroy(struct lttng_event_rule *rule)
25{
26 struct lttng_event_rule_tracepoint *tracepoint;
27
28 if (rule == NULL) {
29 return;
30 }
31
32 tracepoint = container_of(
33 rule, struct lttng_event_rule_tracepoint, parent);
34
35 lttng_dynamic_pointer_array_reset(&tracepoint->exclusions);
36 free(tracepoint->pattern);
37 free(tracepoint->filter_expression);
38 free(tracepoint->internal_filter.filter);
39 free(tracepoint->internal_filter.bytecode);
40 free(tracepoint);
41}
42
43static bool lttng_event_rule_tracepoint_validate(
44 const struct lttng_event_rule *rule)
45{
46 bool valid = false;
47 struct lttng_event_rule_tracepoint *tracepoint;
48
49 if (!rule) {
50 goto end;
51 }
52
53 tracepoint = container_of(
54 rule, struct lttng_event_rule_tracepoint, parent);
55
56 /* Required field. */
57 if (!tracepoint->pattern) {
58 ERR("Invalid tracepoint event rule: a pattern must be set.");
59 goto end;
60 }
61
62 /* Required field. */
63 if (tracepoint->domain == LTTNG_DOMAIN_NONE) {
64 ERR("Invalid tracepoint event rule: a domain must be set.");
65 goto end;
66 }
67
68 valid = true;
69end:
70 return valid;
71}
72
73static int lttng_event_rule_tracepoint_serialize(
74 const struct lttng_event_rule *rule,
75 struct lttng_payload *payload)
76{
77 int ret, i;
78 size_t pattern_len, filter_expression_len, exclusions_len;
79 struct lttng_event_rule_tracepoint *tracepoint;
80 struct lttng_event_rule_tracepoint_comm tracepoint_comm;
81 enum lttng_event_rule_status status;
82 unsigned int exclusion_count;
83 size_t exclusions_appended_len = 0;
84
85 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule)) {
86 ret = -1;
87 goto end;
88 }
89
90 DBG("Serializing tracepoint event rule.");
91 tracepoint = container_of(
92 rule, struct lttng_event_rule_tracepoint, parent);
93
94 status = lttng_event_rule_tracepoint_get_exclusions_count(rule, &exclusion_count);
95 assert(status == LTTNG_EVENT_RULE_STATUS_OK);
96
97 pattern_len = strlen(tracepoint->pattern) + 1;
98
99 if (tracepoint->filter_expression != NULL) {
100 filter_expression_len =
101 strlen(tracepoint->filter_expression) + 1;
102 } else {
103 filter_expression_len = 0;
104 }
105
106 exclusions_len = 0;
107 for (i = 0; i < exclusion_count; i++) {
108 const char *exclusion;
109
110 status = lttng_event_rule_tracepoint_get_exclusion_at_index(
111 rule, i, &exclusion);
112 assert(status == LTTNG_EVENT_RULE_STATUS_OK);
113
114 /* Length field. */
115 exclusions_len += sizeof(uint32_t);
116 /* Payload (null terminated). */
117 exclusions_len += strlen(exclusion) + 1;
118 }
119
120 tracepoint_comm.domain_type = (int8_t) tracepoint->domain;
121 tracepoint_comm.loglevel_type = (int8_t) tracepoint->loglevel.type;
122 tracepoint_comm.loglevel_value = tracepoint->loglevel.value;
123 tracepoint_comm.pattern_len = pattern_len;
124 tracepoint_comm.filter_expression_len = filter_expression_len;
125 tracepoint_comm.exclusions_count = exclusion_count;
126 tracepoint_comm.exclusions_len = exclusions_len;
127
128 ret = lttng_dynamic_buffer_append(&payload->buffer, &tracepoint_comm,
129 sizeof(tracepoint_comm));
130 if (ret) {
131 goto end;
132 }
133
134 ret = lttng_dynamic_buffer_append(
135 &payload->buffer, tracepoint->pattern, pattern_len);
136 if (ret) {
137 goto end;
138 }
139
140 ret = lttng_dynamic_buffer_append(&payload->buffer, tracepoint->filter_expression,
141 filter_expression_len);
142 if (ret) {
143 goto end;
144 }
145
146 for (i = 0; i < exclusion_count; i++) {
147 size_t len;
148 const char *exclusion;
149
150 status = lttng_event_rule_tracepoint_get_exclusion_at_index(
151 rule, i, &exclusion);
152 assert(status == LTTNG_EVENT_RULE_STATUS_OK);
153
154 len = strlen(exclusion) + 1;
155 /* Append exclusion length, includes the null terminator. */
156 ret = lttng_dynamic_buffer_append(
157 &payload->buffer, &len, sizeof(uint32_t));
158 if (ret) {
159 goto end;
160 }
161
162 exclusions_appended_len += sizeof(uint32_t);
163
164 /* Include the '\0' in the payload. */
165 ret = lttng_dynamic_buffer_append(
166 &payload->buffer, exclusion, len);
167 if (ret) {
168 goto end;
169 }
170
171 exclusions_appended_len += len;
172 }
173
174 assert(exclusions_len == exclusions_appended_len);
175
176end:
177 return ret;
178}
179
180static bool lttng_event_rule_tracepoint_is_equal(
181 const struct lttng_event_rule *_a,
182 const struct lttng_event_rule *_b)
183{
184 int i;
185 bool is_equal = false;
186 struct lttng_event_rule_tracepoint *a, *b;
187 unsigned int count_a, count_b;
188 enum lttng_event_rule_status status;
189
190 a = container_of(_a, struct lttng_event_rule_tracepoint, parent);
191 b = container_of(_b, struct lttng_event_rule_tracepoint, parent);
192
193 status = lttng_event_rule_tracepoint_get_exclusions_count(_a, &count_a);
194 assert(status == LTTNG_EVENT_RULE_STATUS_OK);
195 status = lttng_event_rule_tracepoint_get_exclusions_count(_b, &count_b);
196 assert(status == LTTNG_EVENT_RULE_STATUS_OK);
197
198 /* Quick checks. */
199 if (a->domain != b->domain) {
200 goto end;
201 }
202
203 if (count_a != count_b) {
204 goto end;
205 }
206
207 if (!!a->filter_expression != !!b->filter_expression) {
208 goto end;
209 }
210
211 /* Long check. */
212 assert(a->pattern);
213 assert(b->pattern);
214 if (strcmp(a->pattern, b->pattern)) {
215 goto end;
216 }
217
218 if (a->filter_expression && b->filter_expression) {
219 if (strcmp(a->filter_expression, b->filter_expression)) {
220 goto end;
221 }
222 } else if (!!a->filter_expression != !!b->filter_expression) {
223 /* One is set; not the other. */
224 goto end;
225 }
226
227 if (a->loglevel.type != b->loglevel.type) {
228 goto end;
229 }
230
231 if (a->loglevel.value != b->loglevel.value) {
232 goto end;
233 }
234
235 for (i = 0; i < count_a; i++) {
236 const char *exclusion_a, *exclusion_b;
237
238 status = lttng_event_rule_tracepoint_get_exclusion_at_index(
239 _a, i, &exclusion_a);
240 assert(status == LTTNG_EVENT_RULE_STATUS_OK);
241 status = lttng_event_rule_tracepoint_get_exclusion_at_index(
242 _b, i, &exclusion_b);
243 assert(status == LTTNG_EVENT_RULE_STATUS_OK);
244 if (strcmp(exclusion_a, exclusion_b)) {
245 goto end;
246 }
247 }
248
249 is_equal = true;
250end:
251 return is_equal;
252}
253
254/*
255 * On success ret is 0;
256 *
257 * On error ret is negative.
258 *
259 * An event with NO loglevel and the name is * will return NULL.
260 */
261static int generate_agent_filter(
262 const struct lttng_event_rule *rule, char **_agent_filter)
263{
264 int err;
265 int ret = 0;
266 char *agent_filter = NULL;
267 const char *pattern;
268 const char *filter;
269 enum lttng_loglevel_type loglevel_type;
270 enum lttng_event_rule_status status;
271
272 assert(rule);
273 assert(_agent_filter);
274
275 status = lttng_event_rule_tracepoint_get_pattern(rule, &pattern);
276 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
277 ret = -1;
278 goto end;
279 }
280
281 status = lttng_event_rule_tracepoint_get_filter(rule, &filter);
282 if (status == LTTNG_EVENT_RULE_STATUS_UNSET) {
283 filter = NULL;
284 } else if (status != LTTNG_EVENT_RULE_STATUS_OK) {
285 ret = -1;
286 goto end;
287 }
288
289 status = lttng_event_rule_tracepoint_get_log_level_type(
290 rule, &loglevel_type);
291 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
292 ret = -1;
293 goto end;
294 }
295
296 /* Don't add filter for the '*' event. */
297 if (strcmp(pattern, "*") != 0) {
298 if (filter) {
299 err = asprintf(&agent_filter,
300 "(%s) && (logger_name == \"%s\")",
301 filter, pattern);
302 } else {
303 err = asprintf(&agent_filter, "logger_name == \"%s\"",
304 pattern);
305 }
306
307 if (err < 0) {
308 PERROR("Failed to format agent filter string");
309 ret = -1;
310 goto end;
311 }
312 }
313
314 if (loglevel_type != LTTNG_EVENT_LOGLEVEL_ALL) {
315 const char *op;
316 int loglevel_value;
317
318 status = lttng_event_rule_tracepoint_get_log_level(
319 rule, &loglevel_value);
320 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
321 ret = -1;
322 goto end;
323 }
324
325 if (loglevel_type == LTTNG_EVENT_LOGLEVEL_RANGE) {
326 op = ">=";
327 } else {
328 op = "==";
329 }
330
331 if (filter || agent_filter) {
332 char *new_filter;
333
334 err = asprintf(&new_filter,
335 "(%s) && (int_loglevel %s %d)",
336 agent_filter ? agent_filter : filter,
337 op, loglevel_value);
338 if (agent_filter) {
339 free(agent_filter);
340 }
341 agent_filter = new_filter;
342 } else {
343 err = asprintf(&agent_filter, "int_loglevel %s %d", op,
344 loglevel_value);
345 }
346
347 if (err < 0) {
348 PERROR("Failed to format agent filter string");
349 ret = -1;
350 goto end;
351 }
352 }
353
354 *_agent_filter = agent_filter;
355 agent_filter = NULL;
356
357end:
358 free(agent_filter);
359 return ret;
360}
361
362static enum lttng_error_code
363lttng_event_rule_tracepoint_generate_filter_bytecode(
58daac01
JR
364 struct lttng_event_rule *rule,
365 const struct lttng_credentials *creds)
6d420eff
JR
366{
367 int ret;
368 enum lttng_error_code ret_code;
369 struct lttng_event_rule_tracepoint *tracepoint;
370 enum lttng_domain_type domain_type;
371 enum lttng_event_rule_status status;
372 const char *filter;
373 struct lttng_filter_bytecode *bytecode = NULL;
374
375 assert(rule);
376
377 tracepoint = container_of(
378 rule, struct lttng_event_rule_tracepoint, parent);
379
380 status = lttng_event_rule_tracepoint_get_filter(rule, &filter);
381 if (status == LTTNG_EVENT_RULE_STATUS_UNSET) {
382 filter = NULL;
383 } else if (status != LTTNG_EVENT_RULE_STATUS_OK) {
384 ret_code = LTTNG_ERR_FILTER_INVAL;
385 goto end;
386 }
387
388 if (filter && filter[0] == '\0') {
389 ret_code = LTTNG_ERR_FILTER_INVAL;
390 goto error;
391 }
392
393 status = lttng_event_rule_tracepoint_get_domain_type(
394 rule, &domain_type);
395 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
396 ret_code = LTTNG_ERR_UNK;
397 goto error;
398 }
399
400 switch (domain_type) {
401 case LTTNG_DOMAIN_LOG4J:
402 case LTTNG_DOMAIN_JUL:
403 case LTTNG_DOMAIN_PYTHON:
404 {
405 char *agent_filter;
406
407 ret = generate_agent_filter(rule, &agent_filter);
408 if (ret) {
409 ret_code = LTTNG_ERR_FILTER_INVAL;
410 goto error;
411 }
412
413 tracepoint->internal_filter.filter = agent_filter;
414 break;
415 }
416 default:
417 {
418 if (filter) {
419 tracepoint->internal_filter.filter = strdup(filter);
420 if (tracepoint->internal_filter.filter == NULL) {
421 ret_code = LTTNG_ERR_NOMEM;
422 goto error;
423 }
424 } else {
425 tracepoint->internal_filter.filter = NULL;
426 }
427 break;
428 }
429 }
430
431 if (tracepoint->internal_filter.filter == NULL) {
432 ret_code = LTTNG_OK;
433 goto end;
434 }
435
436 ret = run_as_generate_filter_bytecode(
58daac01 437 tracepoint->internal_filter.filter, creds,
6d420eff
JR
438 &bytecode);
439 if (ret) {
440 ret_code = LTTNG_ERR_FILTER_INVAL;
441 goto end;
442 }
443
444 tracepoint->internal_filter.bytecode = bytecode;
445 bytecode = NULL;
446 ret_code = LTTNG_OK;
447
448error:
449end:
450 free(bytecode);
451 return ret_code;
452}
453
454static const char *lttng_event_rule_tracepoint_get_internal_filter(
455 const struct lttng_event_rule *rule)
456{
457 struct lttng_event_rule_tracepoint *tracepoint;
458
459 assert(rule);
460 tracepoint = container_of(
461 rule, struct lttng_event_rule_tracepoint, parent);
462 return tracepoint->internal_filter.filter;
463}
464
465static const struct lttng_filter_bytecode *
466lttng_event_rule_tracepoint_get_internal_filter_bytecode(
467 const struct lttng_event_rule *rule)
468{
469 struct lttng_event_rule_tracepoint *tracepoint;
470
471 assert(rule);
472 tracepoint = container_of(
473 rule, struct lttng_event_rule_tracepoint, parent);
474 return tracepoint->internal_filter.bytecode;
475}
476
993578ff 477static enum lttng_event_rule_generate_exclusions_status
6d420eff 478lttng_event_rule_tracepoint_generate_exclusions(
993578ff
JR
479 const struct lttng_event_rule *rule,
480 struct lttng_event_exclusion **_exclusions)
6d420eff 481{
993578ff
JR
482 unsigned int nb_exclusions = 0, i;
483 enum lttng_domain_type domain_type;
484 struct lttng_event_exclusion *exclusions;
485 enum lttng_event_rule_status event_rule_status;
486 enum lttng_event_rule_generate_exclusions_status ret_status;
6d420eff 487
993578ff
JR
488 assert(_exclusions);
489
490 event_rule_status = lttng_event_rule_tracepoint_get_domain_type(
491 rule, &domain_type);
492 assert(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK);
6d420eff
JR
493
494 switch (domain_type) {
495 case LTTNG_DOMAIN_KERNEL:
496 case LTTNG_DOMAIN_JUL:
497 case LTTNG_DOMAIN_LOG4J:
498 case LTTNG_DOMAIN_PYTHON:
499 /* Not supported. */
993578ff
JR
500 exclusions = NULL;
501 ret_status = LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE;
6d420eff
JR
502 goto end;
503 case LTTNG_DOMAIN_UST:
504 /* Exclusions supported. */
505 break;
506 default:
993578ff 507 /* Unknown domain. */
6d420eff
JR
508 abort();
509 }
510
993578ff 511 event_rule_status = lttng_event_rule_tracepoint_get_exclusions_count(
6d420eff 512 rule, &nb_exclusions);
993578ff 513 assert(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK);
6d420eff
JR
514 if (nb_exclusions == 0) {
515 /* Nothing to do. */
993578ff
JR
516 exclusions = NULL;
517 ret_status = LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE;
6d420eff
JR
518 goto end;
519 }
520
993578ff
JR
521 exclusions = zmalloc(sizeof(struct lttng_event_exclusion) +
522 (LTTNG_SYMBOL_NAME_LEN * nb_exclusions));
523 if (!exclusions) {
6d420eff 524 PERROR("Failed to allocate exclusions buffer");
993578ff 525 ret_status = LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_OUT_OF_MEMORY;
6d420eff
JR
526 goto end;
527 }
528
993578ff 529 exclusions->count = nb_exclusions;
6d420eff 530 for (i = 0; i < nb_exclusions; i++) {
993578ff
JR
531 int copy_ret;
532 const char *exclusion_str;
533
534 event_rule_status =
535 lttng_event_rule_tracepoint_get_exclusion_at_index(
536 rule, i, &exclusion_str);
537 assert(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK);
538
539 copy_ret = lttng_strncpy(exclusions->names[i], exclusion_str,
540 LTTNG_SYMBOL_NAME_LEN);
541 if (copy_ret) {
542 free(exclusions);
543 exclusions = NULL;
544 ret_status = LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_ERROR;
545 goto end;
546 }
6d420eff
JR
547 }
548
993578ff
JR
549 ret_status = LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_OK;
550
6d420eff 551end:
993578ff
JR
552 *_exclusions = exclusions;
553 return ret_status;
6d420eff
JR
554}
555
556static void destroy_lttng_exclusions_element(void *ptr)
557{
558 free(ptr);
559}
560
959e3c66
JR
561static unsigned long lttng_event_rule_tracepoint_hash(
562 const struct lttng_event_rule *rule)
563{
564 unsigned long hash;
565 unsigned int i, exclusion_count;
566 enum lttng_event_rule_status status;
567 struct lttng_event_rule_tracepoint *tp_rule =
568 container_of(rule, typeof(*tp_rule), parent);
569
570 hash = hash_key_ulong((void *) LTTNG_EVENT_RULE_TYPE_TRACEPOINT,
571 lttng_ht_seed);
572 hash ^= hash_key_ulong((void *) tp_rule->domain, lttng_ht_seed);
573 hash ^= hash_key_str(tp_rule->pattern, lttng_ht_seed);
574
575 if (tp_rule->filter_expression) {
576 hash ^= hash_key_str(tp_rule->filter_expression, lttng_ht_seed);
577 }
578
579 hash ^= hash_key_ulong((void *) tp_rule->loglevel.type,
580 lttng_ht_seed);
581 if (tp_rule->loglevel.type != LTTNG_EVENT_LOGLEVEL_ALL) {
582 hash ^= hash_key_ulong(
583 (void *) (unsigned long) tp_rule->loglevel.value,
584 lttng_ht_seed);
585 }
586
587 status = lttng_event_rule_tracepoint_get_exclusions_count(rule,
588 &exclusion_count);
589 assert(status == LTTNG_EVENT_RULE_STATUS_OK);
590
591 for (i = 0; i < exclusion_count; i++) {
592 const char *exclusion;
593
594 status = lttng_event_rule_tracepoint_get_exclusion_at_index(
595 rule, i, &exclusion);
596 assert(status == LTTNG_EVENT_RULE_STATUS_OK);
597 hash ^= hash_key_str(exclusion, lttng_ht_seed);
598 }
599
600 return hash;
601}
602
44760c20
JR
603static struct lttng_event *lttng_event_rule_tracepoint_generate_lttng_event(
604 const struct lttng_event_rule *rule)
605{
606 int ret;
607 const struct lttng_event_rule_tracepoint *tracepoint;
608 struct lttng_event *local_event = NULL;
609 struct lttng_event *event = NULL;
610
611 tracepoint = container_of(
612 rule, const struct lttng_event_rule_tracepoint, parent);
613
614 local_event = zmalloc(sizeof(*local_event));
615 if (!local_event) {
616 goto error;
617 }
618
619 local_event->type = LTTNG_EVENT_TRACEPOINT;
620 ret = lttng_strncpy(local_event->name, tracepoint->pattern,
621 sizeof(local_event->name));
622 if (ret) {
623 ERR("Truncation occurred when copying event rule pattern to `lttng_event` structure: pattern = '%s'",
624 tracepoint->pattern);
625 goto error;
626 }
627
628 local_event->loglevel_type = tracepoint->loglevel.type;
629 local_event->loglevel = tracepoint->loglevel.value;
630
631 event = local_event;
632 local_event = NULL;
633error:
634 free(local_event);
635 return event;
636}
637
6d420eff
JR
638struct lttng_event_rule *lttng_event_rule_tracepoint_create(
639 enum lttng_domain_type domain_type)
640{
641 struct lttng_event_rule *rule = NULL;
642 struct lttng_event_rule_tracepoint *tp_rule;
643
644 if (domain_type == LTTNG_DOMAIN_NONE) {
645 goto end;
646 }
647
648 tp_rule = zmalloc(sizeof(struct lttng_event_rule_tracepoint));
649 if (!tp_rule) {
650 goto end;
651 }
652
653 rule = &tp_rule->parent;
654 lttng_event_rule_init(&tp_rule->parent, LTTNG_EVENT_RULE_TYPE_TRACEPOINT);
655 tp_rule->parent.validate = lttng_event_rule_tracepoint_validate;
656 tp_rule->parent.serialize = lttng_event_rule_tracepoint_serialize;
657 tp_rule->parent.equal = lttng_event_rule_tracepoint_is_equal;
658 tp_rule->parent.destroy = lttng_event_rule_tracepoint_destroy;
659 tp_rule->parent.generate_filter_bytecode =
660 lttng_event_rule_tracepoint_generate_filter_bytecode;
661 tp_rule->parent.get_filter =
662 lttng_event_rule_tracepoint_get_internal_filter;
663 tp_rule->parent.get_filter_bytecode =
664 lttng_event_rule_tracepoint_get_internal_filter_bytecode;
665 tp_rule->parent.generate_exclusions =
666 lttng_event_rule_tracepoint_generate_exclusions;
959e3c66 667 tp_rule->parent.hash = lttng_event_rule_tracepoint_hash;
44760c20
JR
668 tp_rule->parent.generate_lttng_event =
669 lttng_event_rule_tracepoint_generate_lttng_event;
6d420eff
JR
670
671 tp_rule->domain = domain_type;
672 tp_rule->loglevel.type = LTTNG_EVENT_LOGLEVEL_ALL;
673
674 lttng_dynamic_pointer_array_init(&tp_rule->exclusions,
675 destroy_lttng_exclusions_element);
676end:
677 return rule;
678}
679
680LTTNG_HIDDEN
681ssize_t lttng_event_rule_tracepoint_create_from_payload(
682 struct lttng_payload_view *view,
683 struct lttng_event_rule **_event_rule)
684{
685 ssize_t ret, offset = 0;
686 int i;
687 enum lttng_event_rule_status status;
688 enum lttng_domain_type domain_type;
689 enum lttng_loglevel_type loglevel_type;
690 const struct lttng_event_rule_tracepoint_comm *tracepoint_comm;
691 const char *pattern;
692 const char *filter_expression = NULL;
693 const char **exclusions = NULL;
694 const uint32_t *exclusion_len;
695 const char *exclusion;
696 struct lttng_buffer_view current_buffer_view;
697 struct lttng_event_rule *rule = NULL;
698
699 if (!_event_rule) {
700 ret = -1;
701 goto end;
702 }
703
3e6e0df2
JG
704 current_buffer_view = lttng_buffer_view_from_view(
705 &view->buffer, offset, sizeof(*tracepoint_comm));
706 if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
6d420eff
JR
707 ERR("Failed to initialize from malformed event rule tracepoint: buffer too short to contain header.");
708 ret = -1;
709 goto end;
710 }
711
6d420eff
JR
712 tracepoint_comm = (typeof(tracepoint_comm)) current_buffer_view.data;
713
6d420eff
JR
714 if (tracepoint_comm->domain_type <= LTTNG_DOMAIN_NONE ||
715 tracepoint_comm->domain_type > LTTNG_DOMAIN_PYTHON) {
716 /* Invalid domain value. */
717 ERR("Invalid domain type value (%i) found in tracepoint_comm buffer.",
718 (int) tracepoint_comm->domain_type);
719 ret = -1;
720 goto end;
721 }
722
723 domain_type = (enum lttng_domain_type) tracepoint_comm->domain_type;
724 rule = lttng_event_rule_tracepoint_create(domain_type);
725 if (!rule) {
726 ERR("Failed to create event rule tracepoint.");
727 ret = -1;
728 goto end;
729 }
730
731 loglevel_type = (enum lttng_loglevel_type)
732 tracepoint_comm->loglevel_type;
733 switch (loglevel_type) {
734 case LTTNG_EVENT_LOGLEVEL_ALL:
735 status = lttng_event_rule_tracepoint_set_log_level_all(rule);
736 break;
737 case LTTNG_EVENT_LOGLEVEL_RANGE:
738 status = lttng_event_rule_tracepoint_set_log_level_range_lower_bound(rule,
739 (enum lttng_loglevel_type) tracepoint_comm
740 ->loglevel_value);
741 break;
742 case LTTNG_EVENT_LOGLEVEL_SINGLE:
743 status = lttng_event_rule_tracepoint_set_log_level(rule,
744 (enum lttng_loglevel_type) tracepoint_comm
745 ->loglevel_value);
746 break;
747 default:
748 ERR("Failed to set event rule tracepoint loglevel: unknown loglevel type.");
749 ret = -1;
750 goto end;
751 }
752
753 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
754 ERR("Failed to set event rule tracepoint loglevel.");
755 }
756
757 /* Skip to payload. */
758 offset += current_buffer_view.size;
759
760 /* Map the pattern. */
761 current_buffer_view = lttng_buffer_view_from_view(
762 &view->buffer, offset, tracepoint_comm->pattern_len);
3e6e0df2
JG
763
764 if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
6d420eff
JR
765 ret = -1;
766 goto end;
767 }
768
3e6e0df2 769 pattern = current_buffer_view.data;
6d420eff
JR
770 if (!lttng_buffer_view_contains_string(&current_buffer_view, pattern,
771 tracepoint_comm->pattern_len)) {
772 ret = -1;
773 goto end;
774 }
775
776 /* Skip after the pattern. */
777 offset += tracepoint_comm->pattern_len;
778
779 if (!tracepoint_comm->filter_expression_len) {
780 goto skip_filter_expression;
781 }
782
783 /* Map the filter_expression. */
784 current_buffer_view = lttng_buffer_view_from_view(&view->buffer, offset,
785 tracepoint_comm->filter_expression_len);
3e6e0df2 786 if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
6d420eff
JR
787 ret = -1;
788 goto end;
789 }
790
3e6e0df2 791 filter_expression = current_buffer_view.data;
6d420eff
JR
792 if (!lttng_buffer_view_contains_string(&current_buffer_view,
793 filter_expression,
794 tracepoint_comm->filter_expression_len)) {
795 ret = -1;
796 goto end;
797 }
798
799 /* Skip after the pattern. */
800 offset += tracepoint_comm->filter_expression_len;
801
802skip_filter_expression:
803 for (i = 0; i < tracepoint_comm->exclusions_count; i++) {
804 current_buffer_view = lttng_buffer_view_from_view(
805 &view->buffer, offset, sizeof(*exclusion_len));
3e6e0df2 806 if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
6d420eff
JR
807 ret = -1;
808 goto end;
809 }
810
3e6e0df2 811 exclusion_len = (typeof(exclusion_len)) current_buffer_view.data;
6d420eff 812 offset += sizeof(*exclusion_len);
3e6e0df2 813
6d420eff
JR
814 current_buffer_view = lttng_buffer_view_from_view(
815 &view->buffer, offset, *exclusion_len);
3e6e0df2
JG
816 if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
817 ret = -1;
818 goto end;
819 }
820
6d420eff
JR
821 exclusion = current_buffer_view.data;
822 if (!lttng_buffer_view_contains_string(&current_buffer_view,
823 exclusion, *exclusion_len)) {
824 ret = -1;
825 goto end;
826 }
827
828 status = lttng_event_rule_tracepoint_add_exclusion(rule, exclusion);
829 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
830 ERR("Failed to add event rule tracepoint exclusion \"%s\".",
831 exclusion);
832 ret = -1;
833 goto end;
834 }
835
836 /* Skip to next exclusion. */
837 offset += *exclusion_len;
838 }
839
840 status = lttng_event_rule_tracepoint_set_pattern(rule, pattern);
841 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
842 ERR("Failed to set event rule tracepoint pattern.");
843 ret = -1;
844 goto end;
845 }
846
847 if (filter_expression) {
848 status = lttng_event_rule_tracepoint_set_filter(
849 rule, filter_expression);
850 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
851 ERR("Failed to set event rule tracepoint pattern.");
852 ret = -1;
853 goto end;
854 }
855 }
856
857 *_event_rule = rule;
858 rule = NULL;
859 ret = offset;
860end:
861 free(exclusions);
862 lttng_event_rule_destroy(rule);
863 return ret;
864}
865
866enum lttng_event_rule_status lttng_event_rule_tracepoint_set_pattern(
867 struct lttng_event_rule *rule, const char *pattern)
868{
869 char *pattern_copy = NULL;
870 struct lttng_event_rule_tracepoint *tracepoint;
871 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
872
873 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !pattern ||
874 strlen(pattern) == 0) {
875 status = LTTNG_EVENT_RULE_STATUS_INVALID;
876 goto end;
877 }
878
879 tracepoint = container_of(
880 rule, struct lttng_event_rule_tracepoint, parent);
881 pattern_copy = strdup(pattern);
882 if (!pattern_copy) {
883 status = LTTNG_EVENT_RULE_STATUS_ERROR;
884 goto end;
885 }
886
887 free(tracepoint->pattern);
888
889 tracepoint->pattern = pattern_copy;
890 pattern_copy = NULL;
891end:
892 return status;
893}
894
895enum lttng_event_rule_status lttng_event_rule_tracepoint_get_pattern(
896 const struct lttng_event_rule *rule, const char **pattern)
897{
898 struct lttng_event_rule_tracepoint *tracepoint;
899 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
900
901 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !pattern) {
902 status = LTTNG_EVENT_RULE_STATUS_INVALID;
903 goto end;
904 }
905
906 tracepoint = container_of(
907 rule, struct lttng_event_rule_tracepoint, parent);
908 if (!tracepoint->pattern) {
909 status = LTTNG_EVENT_RULE_STATUS_UNSET;
910 goto end;
911 }
912
913 *pattern = tracepoint->pattern;
914end:
915 return status;
916}
917
918enum lttng_event_rule_status lttng_event_rule_tracepoint_get_domain_type(
919 const struct lttng_event_rule *rule,
920 enum lttng_domain_type *type)
921{
922 struct lttng_event_rule_tracepoint *tracepoint;
923 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
924
925 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !type) {
926 status = LTTNG_EVENT_RULE_STATUS_INVALID;
927 goto end;
928 }
929
930 tracepoint = container_of(
931 rule, struct lttng_event_rule_tracepoint, parent);
932 *type = tracepoint->domain;
933end:
934 return status;
935}
936
937enum lttng_event_rule_status lttng_event_rule_tracepoint_set_filter(
938 struct lttng_event_rule *rule, const char *expression)
939{
940 char *expression_copy = NULL;
941 struct lttng_event_rule_tracepoint *tracepoint;
942 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
943
944 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !expression ||
945 strlen(expression) == 0) {
946 status = LTTNG_EVENT_RULE_STATUS_INVALID;
947 goto end;
948 }
949
950 tracepoint = container_of(
951 rule, struct lttng_event_rule_tracepoint, parent);
952 expression_copy = strdup(expression);
953 if (!expression_copy) {
954 PERROR("Failed to copy filter expression");
955 status = LTTNG_EVENT_RULE_STATUS_ERROR;
956 goto end;
957 }
958
959 if (tracepoint->filter_expression) {
960 free(tracepoint->filter_expression);
961 }
962
963 tracepoint->filter_expression = expression_copy;
964 expression_copy = NULL;
965end:
966 return status;
967}
968
969enum lttng_event_rule_status lttng_event_rule_tracepoint_get_filter(
970 const struct lttng_event_rule *rule, const char **expression)
971{
972 struct lttng_event_rule_tracepoint *tracepoint;
973 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
974
975 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !expression) {
976 status = LTTNG_EVENT_RULE_STATUS_INVALID;
977 goto end;
978 }
979
980 tracepoint = container_of(
981 rule, struct lttng_event_rule_tracepoint, parent);
982 if (!tracepoint->filter_expression) {
983 status = LTTNG_EVENT_RULE_STATUS_UNSET;
984 goto end;
985 }
986
987 *expression = tracepoint->filter_expression;
988end:
989 return status;
990}
991
992static bool log_level_value_valid(
993 int level, enum lttng_domain_type domain)
994{
995 bool valid = false;
996
997 switch (domain) {
998 case LTTNG_DOMAIN_KERNEL:
999 case LTTNG_DOMAIN_UST:
1000 if (level < LTTNG_LOGLEVEL_EMERG) {
1001 /* Invalid. */
1002 goto end;
1003 }
1004 if (level > LTTNG_LOGLEVEL_DEBUG) {
1005 /* Invalid. */
1006 goto end;
1007 }
1008
1009 valid = true;
1010 break;
1011 case LTTNG_DOMAIN_JUL:
1012 case LTTNG_DOMAIN_LOG4J:
1013 case LTTNG_DOMAIN_PYTHON:
1014 /*
1015 * For both JUL and LOG4J custom log level are possible and can
1016 * spawn the entire int32 range.
1017 * For python, custom log level are possible, it is not clear if
1018 * negative value are accepted (NOTSET == 0) but the source code
1019 * validate against the int type implying that negative values
1020 * are accepted.
1021 */
1022 valid = true;
1023 goto end;
1024
1025 case LTTNG_DOMAIN_NONE:
1026 default:
1027 abort();
1028 }
1029
1030end:
1031 return valid;
1032}
1033
1034enum lttng_event_rule_status lttng_event_rule_tracepoint_set_log_level(
1035 struct lttng_event_rule *rule, int level)
1036{
1037 struct lttng_event_rule_tracepoint *tracepoint;
1038 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
1039
1040 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule)) {
1041 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1042 goto end;
1043 }
1044
1045 tracepoint = container_of(
1046 rule, struct lttng_event_rule_tracepoint, parent);
1047
1048 if (!log_level_value_valid(level, tracepoint->domain)) {
1049 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1050 goto end;
1051 }
1052
1053 tracepoint->loglevel.value = level;
1054 tracepoint->loglevel.type = LTTNG_EVENT_LOGLEVEL_SINGLE;
1055end:
1056 return status;
1057}
1058
1059enum lttng_event_rule_status
1060lttng_event_rule_tracepoint_set_log_level_range_lower_bound(
1061 struct lttng_event_rule *rule, int level)
1062{
1063 struct lttng_event_rule_tracepoint *tracepoint;
1064 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
1065
1066 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule)) {
1067 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1068 goto end;
1069 }
1070
1071 tracepoint = container_of(
1072 rule, struct lttng_event_rule_tracepoint, parent);
1073
1074 if (!log_level_value_valid(level, tracepoint->domain)) {
1075 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1076 goto end;
1077 }
1078
1079 tracepoint->loglevel.value = level;
1080 tracepoint->loglevel.type = LTTNG_EVENT_LOGLEVEL_RANGE;
1081end:
1082 return status;
1083}
1084
1085enum lttng_event_rule_status lttng_event_rule_tracepoint_set_log_level_all(
1086 struct lttng_event_rule *rule)
1087{
1088 struct lttng_event_rule_tracepoint *tracepoint;
1089 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
1090
1091 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule)) {
1092 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1093 goto end;
1094 }
1095
1096 tracepoint = container_of(
1097 rule, struct lttng_event_rule_tracepoint, parent);
1098 tracepoint->loglevel.type = LTTNG_EVENT_LOGLEVEL_ALL;
1099end:
1100 return status;
1101}
1102
1103enum lttng_event_rule_status lttng_event_rule_tracepoint_get_log_level_type(
1104 const struct lttng_event_rule *rule,
1105 enum lttng_loglevel_type *type)
1106{
1107 struct lttng_event_rule_tracepoint *tracepoint;
1108 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
1109
1110 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !type) {
1111 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1112 goto end;
1113 }
1114
1115 tracepoint = container_of(
1116 rule, struct lttng_event_rule_tracepoint, parent);
1117 *type = tracepoint->loglevel.type;
1118end:
1119 return status;
1120}
1121
1122enum lttng_event_rule_status lttng_event_rule_tracepoint_get_log_level(
1123 const struct lttng_event_rule *rule, int *level)
1124{
1125 struct lttng_event_rule_tracepoint *tracepoint;
1126 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
1127
1128 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !level) {
1129 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1130 goto end;
1131 }
1132
1133 tracepoint = container_of(
1134 rule, struct lttng_event_rule_tracepoint, parent);
1135 if (tracepoint->loglevel.type == LTTNG_EVENT_LOGLEVEL_ALL) {
1136 status = LTTNG_EVENT_RULE_STATUS_UNSET;
1137 goto end;
1138 }
1139
1140 *level = tracepoint->loglevel.value;
1141end:
1142 return status;
1143}
1144
1145enum lttng_event_rule_status lttng_event_rule_tracepoint_add_exclusion(
1146 struct lttng_event_rule *rule,
1147 const char *exclusion)
1148{
1149 int ret;
1150 char *exclusion_copy = NULL;
1151 struct lttng_event_rule_tracepoint *tracepoint;
1152 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
1153 enum lttng_domain_type domain_type;
1154
1155 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) ||
1156 !exclusion) {
1157 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1158 goto end;
1159 }
1160
1161 tracepoint = container_of(
1162 rule, struct lttng_event_rule_tracepoint, parent);
1163
1164 status = lttng_event_rule_tracepoint_get_domain_type(
1165 rule, &domain_type);
1166 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
1167 goto end;
1168 }
1169
1170 switch (domain_type) {
1171 case LTTNG_DOMAIN_KERNEL:
1172 case LTTNG_DOMAIN_JUL:
1173 case LTTNG_DOMAIN_LOG4J:
1174 case LTTNG_DOMAIN_PYTHON:
1175 status = LTTNG_EVENT_RULE_STATUS_UNSUPPORTED;
1176 goto end;
1177 case LTTNG_DOMAIN_UST:
1178 /* Exclusions supported. */
1179 break;
1180 default:
1181 abort();
1182 }
1183
1184 if (strlen(exclusion) >= LTTNG_SYMBOL_NAME_LEN) {
1185 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1186 goto end;
1187 }
1188
1189 exclusion_copy = strdup(exclusion);
1190 if (!exclusion_copy) {
1191 status = LTTNG_EVENT_RULE_STATUS_ERROR;
1192 goto end;
1193 }
1194
1195 ret = lttng_dynamic_pointer_array_add_pointer(&tracepoint->exclusions,
1196 exclusion_copy);
1197 if (ret < 0) {
1198 status = LTTNG_EVENT_RULE_STATUS_ERROR;
1199 goto end;
1200 }
1201
1202 exclusion_copy = NULL;
1203end:
1204 free(exclusion_copy);
1205 return status;
1206}
1207
1208enum lttng_event_rule_status lttng_event_rule_tracepoint_get_exclusions_count(
1209 const struct lttng_event_rule *rule, unsigned int *count)
1210{
1211 struct lttng_event_rule_tracepoint *tracepoint;
1212 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
1213
1214 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !count) {
1215 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1216 goto end;
1217 }
1218
1219 tracepoint = container_of(
1220 rule, struct lttng_event_rule_tracepoint, parent);
1221 *count = lttng_dynamic_pointer_array_get_count(&tracepoint->exclusions);
1222end:
1223 return status;
1224}
1225
1226enum lttng_event_rule_status lttng_event_rule_tracepoint_get_exclusion_at_index(
1227 const struct lttng_event_rule *rule,
1228 unsigned int index,
1229 const char **exclusion)
1230{
1231 unsigned int count;
1232 struct lttng_event_rule_tracepoint *tracepoint;
1233 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
1234
1235 if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !exclusion) {
1236 status = LTTNG_EVENT_RULE_STATUS_INVALID;
1237 goto end;
1238 }
1239
1240 tracepoint = container_of(
1241 rule, struct lttng_event_rule_tracepoint, parent);
1242 if (lttng_event_rule_tracepoint_get_exclusions_count(rule, &count) !=
1243 LTTNG_EVENT_RULE_STATUS_OK) {
1244 goto end;
1245 }
1246
1247 if (index >= count) {
1248 goto end;
1249 }
1250
1251 *exclusion = lttng_dynamic_pointer_array_get_pointer(
1252 &tracepoint->exclusions, index);
1253end:
1254 return status;
1255}
This page took 0.068327 seconds and 4 git commands to generate.