Commit | Line | Data |
---|---|---|
0a23a07d 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 | ||
c9e313bc SM |
8 | #include <common/credentials.hpp> |
9 | #include <common/error.hpp> | |
10 | #include <common/hashtable/hashtable.hpp> | |
11 | #include <common/hashtable/utils.hpp> | |
12 | #include <common/macros.hpp> | |
13 | #include <common/mi-lttng.hpp> | |
14 | #include <common/optional.hpp> | |
15 | #include <common/payload-view.hpp> | |
16 | #include <common/payload.hpp> | |
17 | #include <common/runas.hpp> | |
18 | #include <common/string-utils/string-utils.hpp> | |
28ab034a | 19 | |
c9e313bc SM |
20 | #include <lttng/event-rule/event-rule-internal.hpp> |
21 | #include <lttng/event-rule/user-tracepoint-internal.hpp> | |
0a23a07d | 22 | #include <lttng/event.h> |
6a751b95 | 23 | #include <lttng/log-level-rule.h> |
0a23a07d JR |
24 | |
25 | #define IS_USER_TRACEPOINT_EVENT_RULE(rule) \ | |
26 | (lttng_event_rule_get_type(rule) == LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT) | |
27 | ||
28 | static void lttng_event_rule_user_tracepoint_destroy(struct lttng_event_rule *rule) | |
29 | { | |
30 | struct lttng_event_rule_user_tracepoint *tracepoint; | |
31 | ||
cd9adb8b | 32 | if (rule == nullptr) { |
0a23a07d JR |
33 | return; |
34 | } | |
35 | ||
28ab034a | 36 | tracepoint = lttng::utils::container_of(rule, <tng_event_rule_user_tracepoint::parent); |
0a23a07d JR |
37 | |
38 | lttng_log_level_rule_destroy(tracepoint->log_level_rule); | |
39 | lttng_dynamic_pointer_array_reset(&tracepoint->exclusions); | |
40 | free(tracepoint->pattern); | |
41 | free(tracepoint->filter_expression); | |
42 | free(tracepoint->internal_filter.filter); | |
43 | free(tracepoint->internal_filter.bytecode); | |
44 | free(tracepoint); | |
45 | } | |
46 | ||
28ab034a | 47 | static bool lttng_event_rule_user_tracepoint_validate(const struct lttng_event_rule *rule) |
0a23a07d JR |
48 | { |
49 | bool valid = false; | |
50 | struct lttng_event_rule_user_tracepoint *tracepoint; | |
51 | ||
52 | if (!rule) { | |
53 | goto end; | |
54 | } | |
55 | ||
28ab034a | 56 | tracepoint = lttng::utils::container_of(rule, <tng_event_rule_user_tracepoint::parent); |
0a23a07d JR |
57 | |
58 | /* Required field. */ | |
59 | if (!tracepoint->pattern) { | |
60 | ERR("Invalid user tracepoint event rule: a pattern must be set."); | |
61 | goto end; | |
62 | } | |
63 | ||
64 | valid = true; | |
65 | end: | |
66 | return valid; | |
67 | } | |
68 | ||
28ab034a JG |
69 | static int lttng_event_rule_user_tracepoint_serialize(const struct lttng_event_rule *rule, |
70 | struct lttng_payload *payload) | |
0a23a07d JR |
71 | { |
72 | int ret, i; | |
73 | size_t pattern_len, filter_expression_len, exclusions_len, header_offset; | |
74 | size_t size_before_log_level_rule; | |
75 | struct lttng_event_rule_user_tracepoint *tracepoint; | |
76 | struct lttng_event_rule_user_tracepoint_comm tracepoint_comm; | |
77 | enum lttng_event_rule_status status; | |
78 | unsigned int exclusion_count; | |
79 | size_t exclusions_appended_len = 0; | |
80 | struct lttng_event_rule_user_tracepoint_comm *header; | |
81 | ||
82 | if (!rule || !IS_USER_TRACEPOINT_EVENT_RULE(rule)) { | |
83 | ret = -1; | |
84 | goto end; | |
85 | } | |
86 | ||
87 | header_offset = payload->buffer.size; | |
88 | ||
89 | DBG("Serializing user tracepoint event rule."); | |
28ab034a | 90 | tracepoint = lttng::utils::container_of(rule, <tng_event_rule_user_tracepoint::parent); |
0a23a07d | 91 | |
28ab034a JG |
92 | status = lttng_event_rule_user_tracepoint_get_name_pattern_exclusion_count( |
93 | rule, &exclusion_count); | |
a0377dfe | 94 | LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK); |
0a23a07d JR |
95 | |
96 | pattern_len = strlen(tracepoint->pattern) + 1; | |
97 | ||
cd9adb8b | 98 | if (tracepoint->filter_expression != nullptr) { |
28ab034a | 99 | filter_expression_len = strlen(tracepoint->filter_expression) + 1; |
0a23a07d JR |
100 | } else { |
101 | filter_expression_len = 0; | |
102 | } | |
103 | ||
104 | exclusions_len = 0; | |
105 | for (i = 0; i < exclusion_count; i++) { | |
106 | const char *exclusion; | |
107 | ||
108 | status = lttng_event_rule_user_tracepoint_get_name_pattern_exclusion_at_index( | |
28ab034a | 109 | rule, i, &exclusion); |
a0377dfe | 110 | LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK); |
0a23a07d JR |
111 | |
112 | /* Length field. */ | |
113 | exclusions_len += sizeof(uint32_t); | |
114 | /* Payload (null terminated). */ | |
115 | exclusions_len += strlen(exclusion) + 1; | |
116 | } | |
117 | ||
118 | tracepoint_comm.pattern_len = pattern_len; | |
119 | tracepoint_comm.filter_expression_len = filter_expression_len; | |
120 | tracepoint_comm.exclusions_count = exclusion_count; | |
121 | tracepoint_comm.exclusions_len = exclusions_len; | |
122 | ||
28ab034a JG |
123 | ret = lttng_dynamic_buffer_append( |
124 | &payload->buffer, &tracepoint_comm, sizeof(tracepoint_comm)); | |
0a23a07d JR |
125 | if (ret) { |
126 | goto end; | |
127 | } | |
128 | ||
28ab034a | 129 | ret = lttng_dynamic_buffer_append(&payload->buffer, tracepoint->pattern, pattern_len); |
0a23a07d JR |
130 | if (ret) { |
131 | goto end; | |
132 | } | |
133 | ||
28ab034a JG |
134 | ret = lttng_dynamic_buffer_append( |
135 | &payload->buffer, tracepoint->filter_expression, filter_expression_len); | |
0a23a07d JR |
136 | if (ret) { |
137 | goto end; | |
138 | } | |
139 | ||
140 | size_before_log_level_rule = payload->buffer.size; | |
141 | ||
142 | ret = lttng_log_level_rule_serialize(tracepoint->log_level_rule, payload); | |
143 | if (ret < 0) { | |
144 | goto end; | |
145 | } | |
146 | ||
147 | header = (typeof(header)) ((char *) payload->buffer.data + header_offset); | |
28ab034a | 148 | header->log_level_rule_len = payload->buffer.size - size_before_log_level_rule; |
0a23a07d JR |
149 | |
150 | for (i = 0; i < exclusion_count; i++) { | |
151 | size_t len; | |
7cb80419 | 152 | uint32_t serialized_len; |
0a23a07d JR |
153 | const char *exclusion; |
154 | ||
155 | status = lttng_event_rule_user_tracepoint_get_name_pattern_exclusion_at_index( | |
28ab034a | 156 | rule, i, &exclusion); |
a0377dfe | 157 | LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK); |
0a23a07d JR |
158 | |
159 | len = strlen(exclusion) + 1; | |
7cb80419 MJ |
160 | |
161 | serialized_len = len; | |
0a23a07d | 162 | /* Append exclusion length, includes the null terminator. */ |
7cb80419 | 163 | ret = lttng_dynamic_buffer_append(&payload->buffer, &serialized_len, sizeof(serialized_len)); |
0a23a07d JR |
164 | if (ret) { |
165 | goto end; | |
166 | } | |
167 | ||
168 | exclusions_appended_len += sizeof(uint32_t); | |
169 | ||
170 | /* Include the '\0' in the payload. */ | |
28ab034a | 171 | ret = lttng_dynamic_buffer_append(&payload->buffer, exclusion, len); |
0a23a07d JR |
172 | if (ret) { |
173 | goto end; | |
174 | } | |
175 | ||
176 | exclusions_appended_len += len; | |
177 | } | |
178 | ||
a0377dfe | 179 | LTTNG_ASSERT(exclusions_len == exclusions_appended_len); |
0a23a07d JR |
180 | |
181 | end: | |
182 | return ret; | |
183 | } | |
184 | ||
28ab034a JG |
185 | static bool lttng_event_rule_user_tracepoint_is_equal(const struct lttng_event_rule *_a, |
186 | const struct lttng_event_rule *_b) | |
0a23a07d JR |
187 | { |
188 | int i; | |
189 | bool is_equal = false; | |
190 | struct lttng_event_rule_user_tracepoint *a, *b; | |
191 | unsigned int count_a, count_b; | |
192 | enum lttng_event_rule_status status; | |
193 | ||
0114db0e JG |
194 | a = lttng::utils::container_of(_a, <tng_event_rule_user_tracepoint::parent); |
195 | b = lttng::utils::container_of(_b, <tng_event_rule_user_tracepoint::parent); | |
0a23a07d JR |
196 | |
197 | status = lttng_event_rule_user_tracepoint_get_name_pattern_exclusion_count(_a, &count_a); | |
a0377dfe | 198 | LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK); |
0a23a07d | 199 | status = lttng_event_rule_user_tracepoint_get_name_pattern_exclusion_count(_b, &count_b); |
a0377dfe | 200 | LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK); |
0a23a07d JR |
201 | |
202 | /* Quick checks. */ | |
203 | if (count_a != count_b) { | |
204 | goto end; | |
205 | } | |
206 | ||
207 | if (!!a->filter_expression != !!b->filter_expression) { | |
208 | goto end; | |
209 | } | |
210 | ||
211 | /* Long check. */ | |
a0377dfe FD |
212 | LTTNG_ASSERT(a->pattern); |
213 | LTTNG_ASSERT(b->pattern); | |
5c7248cd | 214 | if (strcmp(a->pattern, b->pattern) != 0) { |
0a23a07d JR |
215 | goto end; |
216 | } | |
217 | ||
218 | if (a->filter_expression && b->filter_expression) { | |
5c7248cd | 219 | if (strcmp(a->filter_expression, b->filter_expression) != 0) { |
0a23a07d JR |
220 | goto end; |
221 | } | |
222 | } else if (!!a->filter_expression != !!b->filter_expression) { | |
223 | /* One is set; not the other. */ | |
224 | goto end; | |
225 | } | |
226 | ||
28ab034a | 227 | if (!lttng_log_level_rule_is_equal(a->log_level_rule, b->log_level_rule)) { |
0a23a07d JR |
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_user_tracepoint_get_name_pattern_exclusion_at_index( | |
28ab034a | 235 | _a, i, &exclusion_a); |
a0377dfe | 236 | LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK); |
0a23a07d | 237 | status = lttng_event_rule_user_tracepoint_get_name_pattern_exclusion_at_index( |
28ab034a | 238 | _b, i, &exclusion_b); |
a0377dfe | 239 | LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK); |
5c7248cd | 240 | if (strcmp(exclusion_a, exclusion_b) != 0) { |
0a23a07d JR |
241 | goto end; |
242 | } | |
243 | } | |
244 | ||
245 | is_equal = true; | |
246 | end: | |
247 | return is_equal; | |
248 | } | |
249 | ||
250 | static enum lttng_error_code | |
28ab034a JG |
251 | lttng_event_rule_user_tracepoint_generate_filter_bytecode(struct lttng_event_rule *rule, |
252 | const struct lttng_credentials *creds) | |
0a23a07d JR |
253 | { |
254 | int ret; | |
255 | enum lttng_error_code ret_code; | |
256 | struct lttng_event_rule_user_tracepoint *tracepoint; | |
257 | enum lttng_event_rule_status status; | |
258 | const char *filter; | |
cd9adb8b | 259 | struct lttng_bytecode *bytecode = nullptr; |
0a23a07d | 260 | |
a0377dfe | 261 | LTTNG_ASSERT(rule); |
0a23a07d | 262 | |
28ab034a | 263 | tracepoint = lttng::utils::container_of(rule, <tng_event_rule_user_tracepoint::parent); |
0a23a07d JR |
264 | |
265 | status = lttng_event_rule_user_tracepoint_get_filter(rule, &filter); | |
266 | if (status == LTTNG_EVENT_RULE_STATUS_UNSET) { | |
cd9adb8b | 267 | filter = nullptr; |
0a23a07d JR |
268 | } else if (status != LTTNG_EVENT_RULE_STATUS_OK) { |
269 | ret_code = LTTNG_ERR_FILTER_INVAL; | |
270 | goto end; | |
271 | } | |
272 | ||
273 | if (filter && filter[0] == '\0') { | |
274 | ret_code = LTTNG_ERR_FILTER_INVAL; | |
275 | goto error; | |
276 | } | |
277 | ||
278 | if (filter) { | |
279 | tracepoint->internal_filter.filter = strdup(filter); | |
cd9adb8b | 280 | if (tracepoint->internal_filter.filter == nullptr) { |
0a23a07d JR |
281 | ret_code = LTTNG_ERR_NOMEM; |
282 | goto error; | |
283 | } | |
284 | } else { | |
cd9adb8b | 285 | tracepoint->internal_filter.filter = nullptr; |
0a23a07d JR |
286 | } |
287 | ||
cd9adb8b | 288 | if (tracepoint->internal_filter.filter == nullptr) { |
0a23a07d JR |
289 | ret_code = LTTNG_OK; |
290 | goto end; | |
291 | } | |
292 | ||
28ab034a | 293 | ret = run_as_generate_filter_bytecode(tracepoint->internal_filter.filter, creds, &bytecode); |
0a23a07d JR |
294 | if (ret) { |
295 | ret_code = LTTNG_ERR_FILTER_INVAL; | |
296 | goto end; | |
297 | } | |
298 | ||
299 | tracepoint->internal_filter.bytecode = bytecode; | |
cd9adb8b | 300 | bytecode = nullptr; |
0a23a07d JR |
301 | ret_code = LTTNG_OK; |
302 | ||
303 | error: | |
304 | end: | |
305 | free(bytecode); | |
306 | return ret_code; | |
307 | } | |
308 | ||
28ab034a JG |
309 | static const char * |
310 | lttng_event_rule_user_tracepoint_get_internal_filter(const struct lttng_event_rule *rule) | |
0a23a07d JR |
311 | { |
312 | struct lttng_event_rule_user_tracepoint *tracepoint; | |
313 | ||
a0377dfe | 314 | LTTNG_ASSERT(rule); |
28ab034a | 315 | tracepoint = lttng::utils::container_of(rule, <tng_event_rule_user_tracepoint::parent); |
0a23a07d JR |
316 | return tracepoint->internal_filter.filter; |
317 | } | |
318 | ||
319 | static const struct lttng_bytecode * | |
28ab034a | 320 | lttng_event_rule_user_tracepoint_get_internal_filter_bytecode(const struct lttng_event_rule *rule) |
0a23a07d JR |
321 | { |
322 | struct lttng_event_rule_user_tracepoint *tracepoint; | |
323 | ||
a0377dfe | 324 | LTTNG_ASSERT(rule); |
28ab034a | 325 | tracepoint = lttng::utils::container_of(rule, <tng_event_rule_user_tracepoint::parent); |
0a23a07d JR |
326 | return tracepoint->internal_filter.bytecode; |
327 | } | |
328 | ||
329 | static enum lttng_event_rule_generate_exclusions_status | |
28ab034a JG |
330 | lttng_event_rule_user_tracepoint_generate_exclusions(const struct lttng_event_rule *rule, |
331 | struct lttng_event_exclusion **_exclusions) | |
0a23a07d JR |
332 | { |
333 | unsigned int nb_exclusions = 0, i; | |
334 | struct lttng_event_exclusion *exclusions; | |
335 | enum lttng_event_rule_status event_rule_status; | |
336 | enum lttng_event_rule_generate_exclusions_status ret_status; | |
337 | ||
a0377dfe | 338 | LTTNG_ASSERT(_exclusions); |
0a23a07d JR |
339 | |
340 | event_rule_status = lttng_event_rule_user_tracepoint_get_name_pattern_exclusion_count( | |
28ab034a | 341 | rule, &nb_exclusions); |
a0377dfe | 342 | LTTNG_ASSERT(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK); |
0a23a07d JR |
343 | if (nb_exclusions == 0) { |
344 | /* Nothing to do. */ | |
cd9adb8b | 345 | exclusions = nullptr; |
0a23a07d JR |
346 | ret_status = LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE; |
347 | goto end; | |
348 | } | |
349 | ||
28ab034a JG |
350 | exclusions = zmalloc<lttng_event_exclusion>(sizeof(struct lttng_event_exclusion) + |
351 | (LTTNG_SYMBOL_NAME_LEN * nb_exclusions)); | |
0a23a07d JR |
352 | if (!exclusions) { |
353 | PERROR("Failed to allocate exclusions buffer"); | |
354 | ret_status = LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_OUT_OF_MEMORY; | |
355 | goto end; | |
356 | } | |
357 | ||
358 | exclusions->count = nb_exclusions; | |
359 | for (i = 0; i < nb_exclusions; i++) { | |
360 | int copy_ret; | |
361 | const char *exclusion_str; | |
362 | ||
363 | event_rule_status = | |
28ab034a JG |
364 | lttng_event_rule_user_tracepoint_get_name_pattern_exclusion_at_index( |
365 | rule, i, &exclusion_str); | |
a0377dfe | 366 | LTTNG_ASSERT(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK); |
0a23a07d | 367 | |
28ab034a JG |
368 | copy_ret = lttng_strncpy(LTTNG_EVENT_EXCLUSION_NAME_AT(exclusions, i), |
369 | exclusion_str, | |
370 | sizeof(LTTNG_EVENT_EXCLUSION_NAME_AT(exclusions, i))); | |
0a23a07d JR |
371 | if (copy_ret) { |
372 | free(exclusions); | |
cd9adb8b | 373 | exclusions = nullptr; |
0a23a07d JR |
374 | ret_status = LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_ERROR; |
375 | goto end; | |
376 | } | |
377 | } | |
378 | ||
379 | ret_status = LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_OK; | |
380 | ||
381 | end: | |
382 | *_exclusions = exclusions; | |
383 | return ret_status; | |
384 | } | |
385 | ||
386 | static void destroy_lttng_exclusions_element(void *ptr) | |
387 | { | |
388 | free(ptr); | |
389 | } | |
390 | ||
28ab034a | 391 | static unsigned long lttng_event_rule_user_tracepoint_hash(const struct lttng_event_rule *rule) |
0a23a07d JR |
392 | { |
393 | unsigned long hash; | |
394 | unsigned int i, exclusion_count; | |
395 | enum lttng_event_rule_status status; | |
396 | struct lttng_event_rule_user_tracepoint *tp_rule = | |
28ab034a | 397 | lttng::utils::container_of(rule, <tng_event_rule_user_tracepoint::parent); |
0a23a07d | 398 | |
28ab034a | 399 | hash = hash_key_ulong((void *) LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT, lttng_ht_seed); |
0a23a07d JR |
400 | hash ^= hash_key_str(tp_rule->pattern, lttng_ht_seed); |
401 | ||
402 | if (tp_rule->filter_expression) { | |
403 | hash ^= hash_key_str(tp_rule->filter_expression, lttng_ht_seed); | |
404 | } | |
405 | ||
406 | if (tp_rule->log_level_rule) { | |
407 | hash ^= lttng_log_level_rule_hash(tp_rule->log_level_rule); | |
408 | } | |
409 | ||
28ab034a JG |
410 | status = lttng_event_rule_user_tracepoint_get_name_pattern_exclusion_count( |
411 | rule, &exclusion_count); | |
a0377dfe | 412 | LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK); |
0a23a07d JR |
413 | |
414 | for (i = 0; i < exclusion_count; i++) { | |
415 | const char *exclusion; | |
416 | ||
417 | status = lttng_event_rule_user_tracepoint_get_name_pattern_exclusion_at_index( | |
28ab034a | 418 | rule, i, &exclusion); |
a0377dfe | 419 | LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK); |
0a23a07d JR |
420 | hash ^= hash_key_str(exclusion, lttng_ht_seed); |
421 | } | |
422 | ||
423 | return hash; | |
424 | } | |
425 | ||
28ab034a JG |
426 | static enum lttng_error_code |
427 | lttng_event_rule_user_tracepoint_mi_serialize(const struct lttng_event_rule *rule, | |
428 | struct mi_writer *writer) | |
6a751b95 JR |
429 | { |
430 | int ret; | |
431 | enum lttng_error_code ret_code; | |
432 | enum lttng_event_rule_status status; | |
cd9adb8b JG |
433 | const char *filter = nullptr; |
434 | const char *name_pattern = nullptr; | |
435 | const struct lttng_log_level_rule *log_level_rule = nullptr; | |
6a751b95 JR |
436 | unsigned int exclusion_count = 0; |
437 | ||
a0377dfe FD |
438 | LTTNG_ASSERT(rule); |
439 | LTTNG_ASSERT(writer); | |
440 | LTTNG_ASSERT(IS_USER_TRACEPOINT_EVENT_RULE(rule)); | |
6a751b95 | 441 | |
28ab034a | 442 | status = lttng_event_rule_user_tracepoint_get_name_pattern(rule, &name_pattern); |
a0377dfe FD |
443 | LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK); |
444 | LTTNG_ASSERT(name_pattern); | |
6a751b95 JR |
445 | |
446 | status = lttng_event_rule_user_tracepoint_get_filter(rule, &filter); | |
a0377dfe | 447 | LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK || |
28ab034a | 448 | status == LTTNG_EVENT_RULE_STATUS_UNSET); |
6a751b95 | 449 | |
28ab034a | 450 | status = lttng_event_rule_user_tracepoint_get_log_level_rule(rule, &log_level_rule); |
a0377dfe | 451 | LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK || |
28ab034a | 452 | status == LTTNG_EVENT_RULE_STATUS_UNSET); |
6a751b95 JR |
453 | |
454 | status = lttng_event_rule_user_tracepoint_get_name_pattern_exclusion_count( | |
28ab034a | 455 | rule, &exclusion_count); |
a0377dfe | 456 | LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK); |
6a751b95 JR |
457 | |
458 | /* Open event rule user tracepoint element. */ | |
28ab034a | 459 | ret = mi_lttng_writer_open_element(writer, mi_lttng_element_event_rule_user_tracepoint); |
6a751b95 JR |
460 | if (ret) { |
461 | goto mi_error; | |
462 | } | |
463 | ||
464 | /* Name pattern. */ | |
28ab034a JG |
465 | ret = mi_lttng_writer_write_element_string( |
466 | writer, mi_lttng_element_event_rule_name_pattern, name_pattern); | |
6a751b95 JR |
467 | if (ret) { |
468 | goto mi_error; | |
469 | } | |
470 | ||
471 | /* Filter expression. */ | |
cd9adb8b | 472 | if (filter != nullptr) { |
28ab034a JG |
473 | ret = mi_lttng_writer_write_element_string( |
474 | writer, mi_lttng_element_event_rule_filter_expression, filter); | |
6a751b95 JR |
475 | if (ret) { |
476 | goto mi_error; | |
477 | } | |
478 | } | |
479 | ||
480 | /* Log level rule. */ | |
481 | if (log_level_rule) { | |
28ab034a | 482 | ret_code = lttng_log_level_rule_mi_serialize(log_level_rule, writer); |
6a751b95 JR |
483 | if (ret_code != LTTNG_OK) { |
484 | goto end; | |
485 | } | |
486 | } | |
487 | ||
488 | if (exclusion_count != 0) { | |
489 | int i; | |
490 | ||
491 | /* Open the exclusion list. */ | |
28ab034a JG |
492 | ret = mi_lttng_writer_open_element( |
493 | writer, | |
494 | mi_lttng_element_event_rule_user_tracepoint_name_pattern_exclusions); | |
6a751b95 JR |
495 | if (ret) { |
496 | goto mi_error; | |
497 | } | |
498 | ||
499 | for (i = 0; i < exclusion_count; i++) { | |
500 | const char *exclusion; | |
501 | ||
28ab034a JG |
502 | status = |
503 | lttng_event_rule_user_tracepoint_get_name_pattern_exclusion_at_index( | |
6a751b95 | 504 | rule, i, &exclusion); |
a0377dfe | 505 | LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK); |
6a751b95 | 506 | |
28ab034a JG |
507 | ret = mi_lttng_writer_write_element_string( |
508 | writer, | |
509 | mi_lttng_element_event_rule_user_tracepoint_name_pattern_exclusion, | |
510 | exclusion); | |
6a751b95 JR |
511 | if (ret) { |
512 | goto mi_error; | |
513 | } | |
514 | } | |
515 | ||
516 | /* Close the list. */ | |
517 | ret = mi_lttng_writer_close_element(writer); | |
518 | if (ret) { | |
519 | goto mi_error; | |
520 | } | |
521 | } | |
522 | ||
523 | /* Close event rule user tracepoint element. */ | |
524 | ret = mi_lttng_writer_close_element(writer); | |
525 | if (ret) { | |
526 | goto mi_error; | |
527 | } | |
528 | ||
529 | ret_code = LTTNG_OK; | |
530 | goto end; | |
531 | ||
532 | mi_error: | |
533 | ret_code = LTTNG_ERR_MI_IO_FAIL; | |
534 | end: | |
535 | return ret_code; | |
536 | } | |
537 | ||
0a23a07d JR |
538 | struct lttng_event_rule *lttng_event_rule_user_tracepoint_create(void) |
539 | { | |
cd9adb8b | 540 | struct lttng_event_rule *rule = nullptr; |
0a23a07d JR |
541 | struct lttng_event_rule_user_tracepoint *tp_rule; |
542 | enum lttng_event_rule_status status; | |
543 | ||
64803277 | 544 | tp_rule = zmalloc<lttng_event_rule_user_tracepoint>(); |
0a23a07d JR |
545 | if (!tp_rule) { |
546 | goto end; | |
547 | } | |
548 | ||
549 | rule = &tp_rule->parent; | |
550 | lttng_event_rule_init(&tp_rule->parent, LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT); | |
551 | tp_rule->parent.validate = lttng_event_rule_user_tracepoint_validate; | |
552 | tp_rule->parent.serialize = lttng_event_rule_user_tracepoint_serialize; | |
553 | tp_rule->parent.equal = lttng_event_rule_user_tracepoint_is_equal; | |
554 | tp_rule->parent.destroy = lttng_event_rule_user_tracepoint_destroy; | |
555 | tp_rule->parent.generate_filter_bytecode = | |
28ab034a JG |
556 | lttng_event_rule_user_tracepoint_generate_filter_bytecode; |
557 | tp_rule->parent.get_filter = lttng_event_rule_user_tracepoint_get_internal_filter; | |
0a23a07d | 558 | tp_rule->parent.get_filter_bytecode = |
28ab034a JG |
559 | lttng_event_rule_user_tracepoint_get_internal_filter_bytecode; |
560 | tp_rule->parent.generate_exclusions = lttng_event_rule_user_tracepoint_generate_exclusions; | |
0a23a07d | 561 | tp_rule->parent.hash = lttng_event_rule_user_tracepoint_hash; |
6a751b95 | 562 | tp_rule->parent.mi_serialize = lttng_event_rule_user_tracepoint_mi_serialize; |
0a23a07d JR |
563 | |
564 | /* Not necessary for now. */ | |
cd9adb8b | 565 | tp_rule->parent.generate_lttng_event = nullptr; |
0a23a07d | 566 | |
cd9adb8b | 567 | tp_rule->log_level_rule = nullptr; |
0a23a07d | 568 | |
28ab034a | 569 | lttng_dynamic_pointer_array_init(&tp_rule->exclusions, destroy_lttng_exclusions_element); |
0a23a07d JR |
570 | |
571 | /* Default pattern is '*'. */ | |
572 | status = lttng_event_rule_user_tracepoint_set_name_pattern(rule, "*"); | |
573 | if (status != LTTNG_EVENT_RULE_STATUS_OK) { | |
574 | lttng_event_rule_destroy(rule); | |
cd9adb8b | 575 | rule = nullptr; |
0a23a07d JR |
576 | } |
577 | ||
578 | end: | |
579 | return rule; | |
580 | } | |
581 | ||
28ab034a JG |
582 | ssize_t lttng_event_rule_user_tracepoint_create_from_payload(struct lttng_payload_view *view, |
583 | struct lttng_event_rule **_event_rule) | |
0a23a07d JR |
584 | { |
585 | ssize_t ret, offset = 0; | |
586 | int i; | |
587 | enum lttng_event_rule_status status; | |
588 | const struct lttng_event_rule_user_tracepoint_comm *tracepoint_comm; | |
589 | const char *pattern; | |
cd9adb8b JG |
590 | const char *filter_expression = nullptr; |
591 | const char **exclusions = nullptr; | |
0a23a07d JR |
592 | const uint32_t *exclusion_len; |
593 | const char *exclusion; | |
594 | struct lttng_buffer_view current_buffer_view; | |
cd9adb8b JG |
595 | struct lttng_event_rule *rule = nullptr; |
596 | struct lttng_log_level_rule *log_level_rule = nullptr; | |
0a23a07d JR |
597 | |
598 | if (!_event_rule) { | |
599 | ret = -1; | |
600 | goto end; | |
601 | } | |
602 | ||
28ab034a JG |
603 | current_buffer_view = |
604 | lttng_buffer_view_from_view(&view->buffer, offset, sizeof(*tracepoint_comm)); | |
0a23a07d JR |
605 | if (!lttng_buffer_view_is_valid(¤t_buffer_view)) { |
606 | ERR("Failed to initialize from malformed event rule tracepoint: buffer too short to contain header."); | |
607 | ret = -1; | |
608 | goto end; | |
609 | } | |
610 | ||
611 | tracepoint_comm = (typeof(tracepoint_comm)) current_buffer_view.data; | |
612 | ||
613 | rule = lttng_event_rule_user_tracepoint_create(); | |
614 | if (!rule) { | |
615 | ERR("Failed to create event rule user tracepoint."); | |
616 | ret = -1; | |
617 | goto end; | |
618 | } | |
619 | ||
620 | /* Skip to payload. */ | |
621 | offset += current_buffer_view.size; | |
622 | ||
623 | /* Map the pattern. */ | |
28ab034a JG |
624 | current_buffer_view = |
625 | lttng_buffer_view_from_view(&view->buffer, offset, tracepoint_comm->pattern_len); | |
0a23a07d JR |
626 | |
627 | if (!lttng_buffer_view_is_valid(¤t_buffer_view)) { | |
628 | ret = -1; | |
629 | goto end; | |
630 | } | |
631 | ||
632 | pattern = current_buffer_view.data; | |
28ab034a JG |
633 | if (!lttng_buffer_view_contains_string( |
634 | ¤t_buffer_view, pattern, tracepoint_comm->pattern_len)) { | |
0a23a07d JR |
635 | ret = -1; |
636 | goto end; | |
637 | } | |
638 | ||
639 | /* Skip after the pattern. */ | |
640 | offset += tracepoint_comm->pattern_len; | |
641 | ||
642 | if (!tracepoint_comm->filter_expression_len) { | |
643 | goto skip_filter_expression; | |
644 | } | |
645 | ||
646 | /* Map the filter_expression. */ | |
28ab034a JG |
647 | current_buffer_view = lttng_buffer_view_from_view( |
648 | &view->buffer, offset, tracepoint_comm->filter_expression_len); | |
0a23a07d JR |
649 | if (!lttng_buffer_view_is_valid(¤t_buffer_view)) { |
650 | ret = -1; | |
651 | goto end; | |
652 | } | |
653 | ||
654 | filter_expression = current_buffer_view.data; | |
655 | if (!lttng_buffer_view_contains_string(¤t_buffer_view, | |
28ab034a JG |
656 | filter_expression, |
657 | tracepoint_comm->filter_expression_len)) { | |
0a23a07d JR |
658 | ret = -1; |
659 | goto end; | |
660 | } | |
661 | ||
662 | /* Skip after the pattern. */ | |
663 | offset += tracepoint_comm->filter_expression_len; | |
664 | ||
665 | skip_filter_expression: | |
666 | if (!tracepoint_comm->log_level_rule_len) { | |
667 | goto skip_log_level_rule; | |
668 | } | |
669 | ||
670 | { | |
671 | /* Map the log level rule. */ | |
28ab034a JG |
672 | struct lttng_payload_view current_payload_view = lttng_payload_view_from_view( |
673 | view, offset, tracepoint_comm->log_level_rule_len); | |
0a23a07d | 674 | |
28ab034a JG |
675 | ret = lttng_log_level_rule_create_from_payload(¤t_payload_view, |
676 | &log_level_rule); | |
0a23a07d JR |
677 | if (ret < 0) { |
678 | ret = -1; | |
679 | goto end; | |
680 | } | |
681 | ||
a0377dfe | 682 | LTTNG_ASSERT(ret == tracepoint_comm->log_level_rule_len); |
0a23a07d JR |
683 | } |
684 | ||
685 | /* Skip after the log level rule. */ | |
686 | offset += tracepoint_comm->log_level_rule_len; | |
687 | ||
688 | skip_log_level_rule: | |
689 | for (i = 0; i < tracepoint_comm->exclusions_count; i++) { | |
28ab034a JG |
690 | current_buffer_view = |
691 | lttng_buffer_view_from_view(&view->buffer, offset, sizeof(*exclusion_len)); | |
0a23a07d JR |
692 | if (!lttng_buffer_view_is_valid(¤t_buffer_view)) { |
693 | ret = -1; | |
694 | goto end; | |
695 | } | |
696 | ||
697 | exclusion_len = (typeof(exclusion_len)) current_buffer_view.data; | |
698 | offset += sizeof(*exclusion_len); | |
699 | ||
28ab034a JG |
700 | current_buffer_view = |
701 | lttng_buffer_view_from_view(&view->buffer, offset, *exclusion_len); | |
0a23a07d JR |
702 | if (!lttng_buffer_view_is_valid(¤t_buffer_view)) { |
703 | ret = -1; | |
704 | goto end; | |
705 | } | |
706 | ||
707 | exclusion = current_buffer_view.data; | |
28ab034a JG |
708 | if (!lttng_buffer_view_contains_string( |
709 | ¤t_buffer_view, exclusion, *exclusion_len)) { | |
0a23a07d JR |
710 | ret = -1; |
711 | goto end; | |
712 | } | |
713 | ||
28ab034a JG |
714 | status = lttng_event_rule_user_tracepoint_add_name_pattern_exclusion(rule, |
715 | exclusion); | |
0a23a07d JR |
716 | if (status != LTTNG_EVENT_RULE_STATUS_OK) { |
717 | ERR("Failed to add event rule user tracepoint exclusion \"%s\".", | |
28ab034a | 718 | exclusion); |
0a23a07d JR |
719 | ret = -1; |
720 | goto end; | |
721 | } | |
722 | ||
723 | /* Skip to next exclusion. */ | |
724 | offset += *exclusion_len; | |
725 | } | |
726 | ||
727 | status = lttng_event_rule_user_tracepoint_set_name_pattern(rule, pattern); | |
728 | if (status != LTTNG_EVENT_RULE_STATUS_OK) { | |
729 | ERR("Failed to set event rule user tracepoint pattern."); | |
730 | ret = -1; | |
731 | goto end; | |
732 | } | |
733 | ||
734 | if (filter_expression) { | |
28ab034a | 735 | status = lttng_event_rule_user_tracepoint_set_filter(rule, filter_expression); |
0a23a07d JR |
736 | if (status != LTTNG_EVENT_RULE_STATUS_OK) { |
737 | ERR("Failed to set event rule user tracepoint pattern."); | |
738 | ret = -1; | |
739 | goto end; | |
740 | } | |
741 | } | |
742 | ||
743 | if (log_level_rule) { | |
28ab034a | 744 | status = lttng_event_rule_user_tracepoint_set_log_level_rule(rule, log_level_rule); |
0a23a07d JR |
745 | if (status != LTTNG_EVENT_RULE_STATUS_OK) { |
746 | ERR("Failed to set event rule user tracepoint log level rule."); | |
747 | ret = -1; | |
748 | goto end; | |
749 | } | |
750 | } | |
751 | ||
752 | *_event_rule = rule; | |
cd9adb8b | 753 | rule = nullptr; |
0a23a07d JR |
754 | ret = offset; |
755 | end: | |
756 | free(exclusions); | |
757 | lttng_log_level_rule_destroy(log_level_rule); | |
758 | lttng_event_rule_destroy(rule); | |
759 | return ret; | |
760 | } | |
761 | ||
28ab034a JG |
762 | enum lttng_event_rule_status |
763 | lttng_event_rule_user_tracepoint_set_name_pattern(struct lttng_event_rule *rule, | |
764 | const char *pattern) | |
0a23a07d | 765 | { |
cd9adb8b | 766 | char *pattern_copy = nullptr; |
0a23a07d JR |
767 | struct lttng_event_rule_user_tracepoint *tracepoint; |
768 | enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; | |
769 | ||
28ab034a | 770 | if (!rule || !IS_USER_TRACEPOINT_EVENT_RULE(rule) || !pattern || strlen(pattern) == 0) { |
0a23a07d JR |
771 | status = LTTNG_EVENT_RULE_STATUS_INVALID; |
772 | goto end; | |
773 | } | |
774 | ||
28ab034a | 775 | tracepoint = lttng::utils::container_of(rule, <tng_event_rule_user_tracepoint::parent); |
0a23a07d JR |
776 | pattern_copy = strdup(pattern); |
777 | if (!pattern_copy) { | |
778 | status = LTTNG_EVENT_RULE_STATUS_ERROR; | |
779 | goto end; | |
780 | } | |
781 | ||
782 | /* Normalize the pattern. */ | |
783 | strutils_normalize_star_glob_pattern(pattern_copy); | |
784 | ||
785 | free(tracepoint->pattern); | |
786 | ||
787 | tracepoint->pattern = pattern_copy; | |
cd9adb8b | 788 | pattern_copy = nullptr; |
0a23a07d JR |
789 | end: |
790 | return status; | |
791 | } | |
792 | ||
28ab034a JG |
793 | enum lttng_event_rule_status |
794 | lttng_event_rule_user_tracepoint_get_name_pattern(const struct lttng_event_rule *rule, | |
795 | const char **pattern) | |
0a23a07d JR |
796 | { |
797 | struct lttng_event_rule_user_tracepoint *tracepoint; | |
798 | enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; | |
799 | ||
800 | if (!rule || !IS_USER_TRACEPOINT_EVENT_RULE(rule) || !pattern) { | |
801 | status = LTTNG_EVENT_RULE_STATUS_INVALID; | |
802 | goto end; | |
803 | } | |
804 | ||
28ab034a | 805 | tracepoint = lttng::utils::container_of(rule, <tng_event_rule_user_tracepoint::parent); |
0a23a07d JR |
806 | if (!tracepoint->pattern) { |
807 | status = LTTNG_EVENT_RULE_STATUS_UNSET; | |
808 | goto end; | |
809 | } | |
810 | ||
811 | *pattern = tracepoint->pattern; | |
812 | end: | |
813 | return status; | |
814 | } | |
815 | ||
28ab034a JG |
816 | enum lttng_event_rule_status |
817 | lttng_event_rule_user_tracepoint_set_filter(struct lttng_event_rule *rule, const char *expression) | |
0a23a07d | 818 | { |
cd9adb8b | 819 | char *expression_copy = nullptr; |
0a23a07d JR |
820 | struct lttng_event_rule_user_tracepoint *tracepoint; |
821 | enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; | |
822 | ||
823 | if (!rule || !IS_USER_TRACEPOINT_EVENT_RULE(rule) || !expression || | |
28ab034a | 824 | strlen(expression) == 0) { |
0a23a07d JR |
825 | status = LTTNG_EVENT_RULE_STATUS_INVALID; |
826 | goto end; | |
827 | } | |
828 | ||
28ab034a | 829 | tracepoint = lttng::utils::container_of(rule, <tng_event_rule_user_tracepoint::parent); |
0a23a07d JR |
830 | expression_copy = strdup(expression); |
831 | if (!expression_copy) { | |
832 | PERROR("Failed to copy filter expression"); | |
833 | status = LTTNG_EVENT_RULE_STATUS_ERROR; | |
834 | goto end; | |
835 | } | |
836 | ||
837 | if (tracepoint->filter_expression) { | |
838 | free(tracepoint->filter_expression); | |
839 | } | |
840 | ||
841 | tracepoint->filter_expression = expression_copy; | |
cd9adb8b | 842 | expression_copy = nullptr; |
0a23a07d JR |
843 | end: |
844 | return status; | |
845 | } | |
846 | ||
28ab034a JG |
847 | enum lttng_event_rule_status |
848 | lttng_event_rule_user_tracepoint_get_filter(const struct lttng_event_rule *rule, | |
849 | const char **expression) | |
0a23a07d JR |
850 | { |
851 | struct lttng_event_rule_user_tracepoint *tracepoint; | |
852 | enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; | |
853 | ||
854 | if (!rule || !IS_USER_TRACEPOINT_EVENT_RULE(rule) || !expression) { | |
855 | status = LTTNG_EVENT_RULE_STATUS_INVALID; | |
856 | goto end; | |
857 | } | |
858 | ||
28ab034a | 859 | tracepoint = lttng::utils::container_of(rule, <tng_event_rule_user_tracepoint::parent); |
0a23a07d JR |
860 | if (!tracepoint->filter_expression) { |
861 | status = LTTNG_EVENT_RULE_STATUS_UNSET; | |
862 | goto end; | |
863 | } | |
864 | ||
865 | *expression = tracepoint->filter_expression; | |
866 | end: | |
867 | return status; | |
868 | } | |
869 | ||
870 | static bool log_level_rule_valid(const struct lttng_log_level_rule *rule) | |
871 | { | |
872 | bool valid = false; | |
873 | enum lttng_log_level_rule_status status; | |
874 | int level; | |
875 | ||
876 | switch (lttng_log_level_rule_get_type(rule)) { | |
877 | case LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY: | |
878 | status = lttng_log_level_rule_exactly_get_level(rule, &level); | |
879 | break; | |
880 | case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS: | |
28ab034a | 881 | status = lttng_log_level_rule_at_least_as_severe_as_get_level(rule, &level); |
0a23a07d JR |
882 | break; |
883 | default: | |
884 | abort(); | |
885 | } | |
886 | ||
a0377dfe | 887 | LTTNG_ASSERT(status == LTTNG_LOG_LEVEL_RULE_STATUS_OK); |
0a23a07d JR |
888 | |
889 | if (level < LTTNG_LOGLEVEL_EMERG) { | |
890 | /* Invalid. */ | |
891 | goto end; | |
892 | } | |
893 | if (level > LTTNG_LOGLEVEL_DEBUG) { | |
894 | /* Invalid. */ | |
895 | goto end; | |
896 | } | |
897 | ||
898 | valid = true; | |
899 | ||
900 | end: | |
901 | return valid; | |
902 | } | |
903 | ||
904 | enum lttng_event_rule_status lttng_event_rule_user_tracepoint_set_log_level_rule( | |
28ab034a | 905 | struct lttng_event_rule *rule, const struct lttng_log_level_rule *log_level_rule) |
0a23a07d JR |
906 | { |
907 | struct lttng_event_rule_user_tracepoint *tracepoint; | |
908 | enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; | |
cd9adb8b | 909 | struct lttng_log_level_rule *copy = nullptr; |
0a23a07d JR |
910 | |
911 | if (!rule || !IS_USER_TRACEPOINT_EVENT_RULE(rule)) { | |
912 | status = LTTNG_EVENT_RULE_STATUS_INVALID; | |
913 | goto end; | |
914 | } | |
915 | ||
28ab034a | 916 | tracepoint = lttng::utils::container_of(rule, <tng_event_rule_user_tracepoint::parent); |
0a23a07d JR |
917 | |
918 | if (!log_level_rule_valid(log_level_rule)) { | |
919 | status = LTTNG_EVENT_RULE_STATUS_INVALID; | |
920 | goto end; | |
921 | } | |
922 | ||
923 | copy = lttng_log_level_rule_copy(log_level_rule); | |
cd9adb8b | 924 | if (copy == nullptr) { |
0a23a07d JR |
925 | status = LTTNG_EVENT_RULE_STATUS_ERROR; |
926 | goto end; | |
927 | } | |
928 | ||
929 | if (tracepoint->log_level_rule) { | |
930 | lttng_log_level_rule_destroy(tracepoint->log_level_rule); | |
931 | } | |
932 | ||
933 | tracepoint->log_level_rule = copy; | |
934 | ||
935 | end: | |
936 | return status; | |
937 | } | |
938 | ||
939 | enum lttng_event_rule_status lttng_event_rule_user_tracepoint_get_log_level_rule( | |
28ab034a | 940 | const struct lttng_event_rule *rule, const struct lttng_log_level_rule **log_level_rule) |
0a23a07d JR |
941 | { |
942 | struct lttng_event_rule_user_tracepoint *tracepoint; | |
943 | enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; | |
944 | ||
945 | if (!rule || !IS_USER_TRACEPOINT_EVENT_RULE(rule) || !log_level_rule) { | |
946 | status = LTTNG_EVENT_RULE_STATUS_INVALID; | |
947 | goto end; | |
948 | } | |
949 | ||
28ab034a | 950 | tracepoint = lttng::utils::container_of(rule, <tng_event_rule_user_tracepoint::parent); |
cd9adb8b | 951 | if (tracepoint->log_level_rule == nullptr) { |
0a23a07d JR |
952 | status = LTTNG_EVENT_RULE_STATUS_UNSET; |
953 | goto end; | |
954 | } | |
955 | ||
956 | *log_level_rule = tracepoint->log_level_rule; | |
957 | end: | |
958 | return status; | |
959 | } | |
960 | ||
28ab034a JG |
961 | enum lttng_event_rule_status |
962 | lttng_event_rule_user_tracepoint_add_name_pattern_exclusion(struct lttng_event_rule *rule, | |
963 | const char *exclusion) | |
0a23a07d JR |
964 | { |
965 | int ret; | |
cd9adb8b | 966 | char *exclusion_copy = nullptr; |
0a23a07d JR |
967 | struct lttng_event_rule_user_tracepoint *tracepoint; |
968 | enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; | |
969 | ||
28ab034a | 970 | if (!rule || !IS_USER_TRACEPOINT_EVENT_RULE(rule) || !exclusion) { |
0a23a07d JR |
971 | status = LTTNG_EVENT_RULE_STATUS_INVALID; |
972 | goto end; | |
973 | } | |
974 | ||
28ab034a | 975 | tracepoint = lttng::utils::container_of(rule, <tng_event_rule_user_tracepoint::parent); |
0a23a07d JR |
976 | |
977 | if (strlen(exclusion) >= LTTNG_SYMBOL_NAME_LEN) { | |
978 | status = LTTNG_EVENT_RULE_STATUS_INVALID; | |
979 | goto end; | |
980 | } | |
981 | ||
982 | exclusion_copy = strdup(exclusion); | |
983 | if (!exclusion_copy) { | |
984 | status = LTTNG_EVENT_RULE_STATUS_ERROR; | |
985 | goto end; | |
986 | } | |
987 | ||
28ab034a | 988 | ret = lttng_dynamic_pointer_array_add_pointer(&tracepoint->exclusions, exclusion_copy); |
0a23a07d JR |
989 | if (ret < 0) { |
990 | status = LTTNG_EVENT_RULE_STATUS_ERROR; | |
991 | goto end; | |
992 | } | |
993 | ||
cd9adb8b | 994 | exclusion_copy = nullptr; |
0a23a07d JR |
995 | end: |
996 | free(exclusion_copy); | |
997 | return status; | |
998 | } | |
999 | ||
1000 | enum lttng_event_rule_status lttng_event_rule_user_tracepoint_get_name_pattern_exclusion_count( | |
28ab034a | 1001 | const struct lttng_event_rule *rule, unsigned int *count) |
0a23a07d JR |
1002 | { |
1003 | struct lttng_event_rule_user_tracepoint *tracepoint; | |
1004 | enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; | |
1005 | ||
1006 | if (!rule || !IS_USER_TRACEPOINT_EVENT_RULE(rule) || !count) { | |
1007 | status = LTTNG_EVENT_RULE_STATUS_INVALID; | |
1008 | goto end; | |
1009 | } | |
1010 | ||
28ab034a | 1011 | tracepoint = lttng::utils::container_of(rule, <tng_event_rule_user_tracepoint::parent); |
0a23a07d JR |
1012 | *count = lttng_dynamic_pointer_array_get_count(&tracepoint->exclusions); |
1013 | end: | |
1014 | return status; | |
1015 | } | |
1016 | ||
1017 | enum lttng_event_rule_status lttng_event_rule_user_tracepoint_get_name_pattern_exclusion_at_index( | |
28ab034a | 1018 | const struct lttng_event_rule *rule, unsigned int index, const char **exclusion) |
0a23a07d JR |
1019 | { |
1020 | unsigned int count; | |
1021 | struct lttng_event_rule_user_tracepoint *tracepoint; | |
1022 | enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; | |
1023 | ||
1024 | if (!rule || !IS_USER_TRACEPOINT_EVENT_RULE(rule) || !exclusion) { | |
1025 | status = LTTNG_EVENT_RULE_STATUS_INVALID; | |
1026 | goto end; | |
1027 | } | |
1028 | ||
28ab034a | 1029 | tracepoint = lttng::utils::container_of(rule, <tng_event_rule_user_tracepoint::parent); |
0a23a07d | 1030 | if (lttng_event_rule_user_tracepoint_get_name_pattern_exclusion_count(rule, &count) != |
28ab034a | 1031 | LTTNG_EVENT_RULE_STATUS_OK) { |
0a23a07d JR |
1032 | goto end; |
1033 | } | |
1034 | ||
1035 | if (index >= count) { | |
1036 | goto end; | |
1037 | } | |
1038 | ||
28ab034a JG |
1039 | *exclusion = (const char *) lttng_dynamic_pointer_array_get_pointer(&tracepoint->exclusions, |
1040 | index); | |
0a23a07d JR |
1041 | end: |
1042 | return status; | |
1043 | } |