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