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