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