Commit | Line | Data |
---|---|---|
0de2479d SM |
1 | /* |
2 | * Copyright (C) 2021 Simon Marchi <simon.marchi@efficios.com> | |
3 | * | |
4 | * SPDX-License-Identifier: GPL-2.0-only | |
5 | * | |
6 | */ | |
7 | ||
8 | #include <stdio.h> | |
9 | ||
10 | #include "../command.h" | |
11 | ||
12 | #include "common/argpar/argpar.h" | |
13 | #include "common/dynamic-array.h" | |
14 | #include "common/mi-lttng.h" | |
15 | /* For lttng_condition_type_str(). */ | |
16 | #include "lttng/condition/condition-internal.h" | |
17 | /* For lttng_domain_type_str(). */ | |
18 | #include "lttng/domain-internal.h" | |
85b05318 | 19 | #include "../loglevel.h" |
0de2479d SM |
20 | |
21 | #ifdef LTTNG_EMBED_HELP | |
22 | static const char help_msg[] = | |
279eb769 | 23 | #include <lttng-list-triggers.1.h> |
0de2479d SM |
24 | ; |
25 | #endif | |
26 | ||
27 | enum { | |
28 | OPT_HELP, | |
29 | OPT_LIST_OPTIONS, | |
30 | }; | |
31 | ||
32 | static const | |
33 | struct argpar_opt_descr list_trigger_options[] = { | |
34 | { OPT_HELP, 'h', "help", false }, | |
35 | { OPT_LIST_OPTIONS, '\0', "list-options", false }, | |
36 | ARGPAR_OPT_DESCR_SENTINEL, | |
37 | }; | |
38 | ||
85b05318 JR |
39 | /* |
40 | * Returns the human-readable log level name associated with a numerical value | |
41 | * if there is one. The Log4j and JUL domains have discontinuous log level | |
42 | * values (a value can fall between two labels). In those cases, NULL is | |
43 | * returned. | |
44 | */ | |
45 | static const char *get_pretty_loglevel_name( | |
46 | enum lttng_domain_type domain, int loglevel) | |
47 | { | |
48 | const char *name = NULL; | |
49 | ||
50 | switch (domain) { | |
51 | case LTTNG_DOMAIN_UST: | |
52 | name = loglevel_value_to_name(loglevel); | |
53 | break; | |
54 | case LTTNG_DOMAIN_LOG4J: | |
55 | name = loglevel_log4j_value_to_name(loglevel); | |
56 | break; | |
57 | case LTTNG_DOMAIN_JUL: | |
58 | name = loglevel_jul_value_to_name(loglevel); | |
59 | break; | |
60 | case LTTNG_DOMAIN_PYTHON: | |
61 | name = loglevel_python_value_to_name(loglevel); | |
62 | break; | |
63 | default: | |
64 | break; | |
65 | } | |
66 | ||
67 | return name; | |
68 | } | |
69 | ||
0de2479d SM |
70 | static |
71 | void print_event_rule_tracepoint(const struct lttng_event_rule *event_rule) | |
72 | { | |
73 | enum lttng_event_rule_status event_rule_status; | |
74 | enum lttng_domain_type domain_type; | |
75 | const char *pattern; | |
76 | const char *filter; | |
77 | int log_level; | |
85b05318 | 78 | const struct lttng_log_level_rule *log_level_rule = NULL; |
0de2479d SM |
79 | unsigned int exclusions_count; |
80 | int i; | |
81 | ||
82 | event_rule_status = lttng_event_rule_tracepoint_get_pattern( | |
83 | event_rule, &pattern); | |
84 | assert(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK); | |
85 | ||
86 | event_rule_status = lttng_event_rule_tracepoint_get_domain_type( | |
87 | event_rule, &domain_type); | |
88 | assert(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK); | |
89 | ||
90 | _MSG(" rule: %s (type: tracepoint, domain: %s", pattern, | |
91 | lttng_domain_type_str(domain_type)); | |
92 | ||
93 | event_rule_status = lttng_event_rule_tracepoint_get_filter( | |
94 | event_rule, &filter); | |
95 | if (event_rule_status == LTTNG_EVENT_RULE_STATUS_OK) { | |
96 | _MSG(", filter: %s", filter); | |
97 | } else { | |
98 | assert(event_rule_status == LTTNG_EVENT_RULE_STATUS_UNSET); | |
99 | } | |
100 | ||
85b05318 JR |
101 | event_rule_status = lttng_event_rule_tracepoint_get_log_level_rule( |
102 | event_rule, &log_level_rule); | |
0de2479d | 103 | if (event_rule_status == LTTNG_EVENT_RULE_STATUS_OK) { |
85b05318 | 104 | enum lttng_log_level_rule_status llr_status; |
0de2479d | 105 | const char *log_level_op; |
85b05318 JR |
106 | const char *pretty_loglevel_name; |
107 | ||
108 | switch (lttng_log_level_rule_get_type(log_level_rule)) { | |
109 | case LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY: | |
110 | log_level_op = "is"; | |
111 | llr_status = lttng_log_level_rule_exactly_get_level( | |
112 | log_level_rule, &log_level); | |
113 | break; | |
114 | case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS: | |
115 | log_level_op = "at least"; | |
116 | llr_status = lttng_log_level_rule_at_least_as_severe_as_get_level( | |
117 | log_level_rule, &log_level); | |
118 | break; | |
119 | default: | |
120 | abort(); | |
121 | } | |
122 | ||
123 | assert(llr_status == LTTNG_LOG_LEVEL_RULE_STATUS_OK); | |
124 | ||
125 | pretty_loglevel_name = get_pretty_loglevel_name( | |
126 | domain_type, log_level); | |
127 | if (pretty_loglevel_name) { | |
128 | _MSG(", log level %s %s", log_level_op, | |
129 | pretty_loglevel_name); | |
130 | } else { | |
131 | _MSG(", log level %s %d", log_level_op, log_level); | |
132 | } | |
0de2479d SM |
133 | } else { |
134 | assert(event_rule_status == LTTNG_EVENT_RULE_STATUS_UNSET); | |
135 | } | |
136 | ||
137 | event_rule_status = lttng_event_rule_tracepoint_get_exclusions_count( | |
138 | event_rule, &exclusions_count); | |
139 | assert(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK); | |
140 | if (exclusions_count > 0) { | |
141 | _MSG(", exclusions: "); | |
142 | for (i = 0; i < exclusions_count; i++) { | |
143 | const char *exclusion; | |
144 | ||
145 | event_rule_status = lttng_event_rule_tracepoint_get_exclusion_at_index( | |
146 | event_rule, i, &exclusion); | |
147 | assert(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK); | |
148 | ||
149 | _MSG("%s%s", i > 0 ? "," : "", exclusion); | |
150 | } | |
151 | } | |
152 | ||
153 | MSG(")"); | |
154 | } | |
155 | ||
156 | static void print_kernel_probe_location( | |
157 | const struct lttng_kernel_probe_location *location) | |
158 | { | |
159 | enum lttng_kernel_probe_location_status status; | |
160 | switch (lttng_kernel_probe_location_get_type(location)) { | |
161 | case LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS: | |
162 | { | |
163 | uint64_t address; | |
164 | ||
165 | status = lttng_kernel_probe_location_address_get_address( | |
166 | location, &address); | |
167 | if (status != LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK) { | |
168 | ERR("Getting kernel probe location address failed."); | |
169 | goto end; | |
170 | } | |
171 | ||
172 | _MSG("0x%" PRIx64, address); | |
173 | ||
174 | break; | |
175 | } | |
176 | case LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET: | |
177 | { | |
178 | uint64_t offset; | |
179 | const char *symbol_name; | |
180 | ||
181 | symbol_name = lttng_kernel_probe_location_symbol_get_name( | |
182 | location); | |
183 | if (!symbol_name) { | |
184 | ERR("Getting kernel probe location symbol name failed."); | |
185 | goto end; | |
186 | } | |
187 | ||
188 | status = lttng_kernel_probe_location_symbol_get_offset( | |
189 | location, &offset); | |
190 | if (status != LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK) { | |
191 | ERR("Getting kernel probe location address failed."); | |
192 | goto end; | |
193 | } | |
194 | ||
195 | if (offset == 0) { | |
196 | _MSG("%s", symbol_name); | |
197 | } else { | |
198 | _MSG("%s+0x%" PRIx64, symbol_name, offset); | |
199 | } | |
200 | ||
201 | break; | |
202 | } | |
203 | default: | |
204 | abort(); | |
205 | }; | |
206 | end: | |
207 | return; | |
208 | } | |
209 | ||
210 | static | |
f2791161 | 211 | void print_event_rule_kernel_probe(const struct lttng_event_rule *event_rule) |
0de2479d SM |
212 | { |
213 | enum lttng_event_rule_status event_rule_status; | |
214 | const char *name; | |
215 | const struct lttng_kernel_probe_location *location; | |
216 | ||
f2791161 | 217 | assert(lttng_event_rule_get_type(event_rule) == LTTNG_EVENT_RULE_TYPE_KERNEL_PROBE); |
0de2479d | 218 | |
d891bb52 | 219 | event_rule_status = lttng_event_rule_kernel_probe_get_event_name(event_rule, &name); |
0de2479d SM |
220 | if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) { |
221 | ERR("Failed to get kprobe event rule's name."); | |
222 | goto end; | |
223 | } | |
224 | ||
f2791161 | 225 | event_rule_status = lttng_event_rule_kernel_probe_get_location( |
0de2479d SM |
226 | event_rule, &location); |
227 | if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) { | |
228 | ERR("Failed to get kprobe event rule's location."); | |
229 | goto end; | |
230 | } | |
231 | ||
232 | _MSG(" rule: %s (type: probe, location: ", name); | |
233 | ||
234 | print_kernel_probe_location(location); | |
235 | ||
236 | MSG(")"); | |
237 | ||
238 | end: | |
239 | return; | |
240 | } | |
241 | ||
242 | static | |
1f1567a5 | 243 | void print_event_rule_userspace_probe(const struct lttng_event_rule *event_rule) |
0de2479d SM |
244 | { |
245 | enum lttng_event_rule_status event_rule_status; | |
246 | const char *name; | |
247 | const struct lttng_userspace_probe_location *location; | |
248 | enum lttng_userspace_probe_location_type userspace_probe_location_type; | |
249 | ||
1f1567a5 | 250 | assert(lttng_event_rule_get_type(event_rule) == LTTNG_EVENT_RULE_TYPE_USERSPACE_PROBE); |
0de2479d | 251 | |
405f9e7d JR |
252 | event_rule_status = lttng_event_rule_userspace_probe_get_event_name( |
253 | event_rule, &name); | |
0de2479d SM |
254 | if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) { |
255 | ERR("Failed to get uprobe event rule's name."); | |
256 | goto end; | |
257 | } | |
258 | ||
1f1567a5 | 259 | event_rule_status = lttng_event_rule_userspace_probe_get_location( |
0de2479d SM |
260 | event_rule, &location); |
261 | if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) { | |
262 | ERR("Failed to get uprobe event rule's location."); | |
263 | goto end; | |
264 | } | |
265 | ||
266 | _MSG(" rule: %s (type: userspace probe, location: ", name); | |
267 | ||
268 | userspace_probe_location_type = | |
269 | lttng_userspace_probe_location_get_type(location); | |
270 | ||
271 | switch (userspace_probe_location_type) { | |
272 | case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION: | |
273 | { | |
274 | const char *binary_path, *function_name; | |
275 | ||
276 | binary_path = lttng_userspace_probe_location_function_get_binary_path( | |
277 | location); | |
278 | function_name = lttng_userspace_probe_location_function_get_function_name( | |
279 | location); | |
280 | ||
281 | _MSG("%s:%s", binary_path, function_name); | |
282 | break; | |
283 | } | |
284 | case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT: | |
285 | _MSG("SDT not implemented yet"); | |
286 | break; | |
287 | default: | |
288 | abort(); | |
289 | } | |
290 | ||
291 | MSG(")"); | |
292 | ||
293 | end: | |
294 | return; | |
295 | } | |
296 | ||
297 | static | |
298 | void print_event_rule_syscall(const struct lttng_event_rule *event_rule) | |
299 | { | |
300 | const char *pattern, *filter; | |
301 | enum lttng_event_rule_status event_rule_status; | |
302 | ||
303 | assert(lttng_event_rule_get_type(event_rule) == LTTNG_EVENT_RULE_TYPE_SYSCALL); | |
304 | ||
305 | event_rule_status = lttng_event_rule_syscall_get_pattern( | |
306 | event_rule, &pattern); | |
307 | assert(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK); | |
308 | ||
309 | _MSG(" rule: %s (type: syscall", pattern); | |
310 | ||
311 | event_rule_status = lttng_event_rule_syscall_get_filter( | |
312 | event_rule, &filter); | |
313 | if (event_rule_status == LTTNG_EVENT_RULE_STATUS_OK) { | |
314 | _MSG(", filter: %s", filter); | |
315 | } else { | |
316 | assert(event_rule_status == LTTNG_EVENT_RULE_STATUS_UNSET); | |
317 | } | |
318 | ||
319 | MSG(")"); | |
320 | } | |
321 | ||
322 | static | |
323 | void print_event_rule(const struct lttng_event_rule *event_rule) | |
324 | { | |
325 | const enum lttng_event_rule_type event_rule_type = | |
326 | lttng_event_rule_get_type(event_rule); | |
327 | ||
328 | switch (event_rule_type) { | |
329 | case LTTNG_EVENT_RULE_TYPE_TRACEPOINT: | |
330 | print_event_rule_tracepoint(event_rule); | |
331 | break; | |
f2791161 JR |
332 | case LTTNG_EVENT_RULE_TYPE_KERNEL_PROBE: |
333 | print_event_rule_kernel_probe(event_rule); | |
0de2479d | 334 | break; |
1f1567a5 JR |
335 | case LTTNG_EVENT_RULE_TYPE_USERSPACE_PROBE: |
336 | print_event_rule_userspace_probe(event_rule); | |
0de2479d SM |
337 | break; |
338 | case LTTNG_EVENT_RULE_TYPE_SYSCALL: | |
339 | print_event_rule_syscall(event_rule); | |
340 | break; | |
341 | default: | |
342 | abort(); | |
343 | } | |
344 | } | |
345 | ||
b203b4b0 SM |
346 | static |
347 | void print_one_event_expr(const struct lttng_event_expr *event_expr) | |
348 | { | |
349 | enum lttng_event_expr_type type; | |
350 | ||
351 | type = lttng_event_expr_get_type(event_expr); | |
352 | ||
353 | switch (type) { | |
354 | case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD: | |
355 | { | |
356 | const char *name; | |
357 | ||
358 | name = lttng_event_expr_event_payload_field_get_name( | |
359 | event_expr); | |
360 | _MSG("%s", name); | |
361 | ||
362 | break; | |
363 | } | |
364 | case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD: | |
365 | { | |
366 | const char *name; | |
367 | ||
368 | name = lttng_event_expr_channel_context_field_get_name( | |
369 | event_expr); | |
370 | _MSG("$ctx.%s", name); | |
371 | ||
372 | break; | |
373 | } | |
374 | case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD: | |
375 | { | |
376 | const char *provider_name; | |
377 | const char *type_name; | |
378 | ||
379 | provider_name = lttng_event_expr_app_specific_context_field_get_provider_name( | |
380 | event_expr); | |
381 | type_name = lttng_event_expr_app_specific_context_field_get_type_name( | |
382 | event_expr); | |
383 | ||
384 | _MSG("$app.%s:%s", provider_name, type_name); | |
385 | ||
386 | break; | |
387 | } | |
388 | case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT: | |
389 | { | |
390 | unsigned int index; | |
391 | const struct lttng_event_expr *parent_expr; | |
392 | enum lttng_event_expr_status status; | |
393 | ||
394 | parent_expr = lttng_event_expr_array_field_element_get_parent_expr( | |
395 | event_expr); | |
396 | assert(parent_expr != NULL); | |
397 | ||
398 | print_one_event_expr(parent_expr); | |
399 | ||
400 | status = lttng_event_expr_array_field_element_get_index( | |
401 | event_expr, &index); | |
402 | assert(status == LTTNG_EVENT_EXPR_STATUS_OK); | |
403 | ||
404 | _MSG("[%u]", index); | |
405 | ||
406 | break; | |
407 | } | |
408 | default: | |
409 | abort(); | |
410 | } | |
411 | } | |
412 | ||
0de2479d | 413 | static |
d602bd6a | 414 | void print_condition_on_event(const struct lttng_condition *condition) |
0de2479d SM |
415 | { |
416 | const struct lttng_event_rule *event_rule; | |
417 | enum lttng_condition_status condition_status; | |
b203b4b0 | 418 | unsigned int cap_desc_count, i; |
0de2479d SM |
419 | |
420 | condition_status = | |
d602bd6a | 421 | lttng_condition_on_event_get_rule(condition, &event_rule); |
0de2479d SM |
422 | assert(condition_status == LTTNG_CONDITION_STATUS_OK); |
423 | ||
424 | print_event_rule(event_rule); | |
b203b4b0 SM |
425 | |
426 | condition_status = | |
d602bd6a | 427 | lttng_condition_on_event_get_capture_descriptor_count( |
b203b4b0 SM |
428 | condition, &cap_desc_count); |
429 | assert(condition_status == LTTNG_CONDITION_STATUS_OK); | |
430 | ||
431 | if (cap_desc_count > 0) { | |
432 | MSG(" captures:"); | |
433 | ||
434 | for (i = 0; i < cap_desc_count; i++) { | |
435 | const struct lttng_event_expr *cap_desc = | |
d602bd6a | 436 | lttng_condition_on_event_get_capture_descriptor_at_index( |
b203b4b0 SM |
437 | condition, i); |
438 | ||
439 | _MSG(" - "); | |
440 | print_one_event_expr(cap_desc); | |
441 | MSG(""); | |
442 | } | |
443 | } | |
0de2479d SM |
444 | } |
445 | ||
446 | static | |
447 | void print_one_action(const struct lttng_action *action) | |
448 | { | |
449 | enum lttng_action_type action_type; | |
450 | enum lttng_action_status action_status; | |
451 | const char *value; | |
452 | ||
453 | action_type = lttng_action_get_type(action); | |
454 | assert(action_type != LTTNG_ACTION_TYPE_GROUP); | |
455 | ||
456 | switch (action_type) { | |
457 | case LTTNG_ACTION_TYPE_NOTIFY: | |
458 | MSG("notify"); | |
459 | break; | |
460 | case LTTNG_ACTION_TYPE_START_SESSION: | |
461 | action_status = lttng_action_start_session_get_session_name( | |
462 | action, &value); | |
463 | assert(action_status == LTTNG_ACTION_STATUS_OK); | |
464 | MSG("start session `%s`", value); | |
465 | break; | |
466 | case LTTNG_ACTION_TYPE_STOP_SESSION: | |
467 | action_status = lttng_action_stop_session_get_session_name( | |
468 | action, &value); | |
469 | assert(action_status == LTTNG_ACTION_STATUS_OK); | |
470 | MSG("stop session `%s`", value); | |
471 | break; | |
472 | case LTTNG_ACTION_TYPE_ROTATE_SESSION: | |
473 | action_status = lttng_action_rotate_session_get_session_name( | |
474 | action, &value); | |
475 | assert(action_status == LTTNG_ACTION_STATUS_OK); | |
476 | MSG("rotate session `%s`", value); | |
477 | break; | |
478 | case LTTNG_ACTION_TYPE_SNAPSHOT_SESSION: | |
479 | { | |
480 | const struct lttng_snapshot_output *output; | |
481 | ||
482 | action_status = lttng_action_snapshot_session_get_session_name( | |
483 | action, &value); | |
484 | assert(action_status == LTTNG_ACTION_STATUS_OK); | |
485 | _MSG("snapshot session `%s`", value); | |
486 | ||
487 | action_status = lttng_action_snapshot_session_get_output( | |
488 | action, &output); | |
489 | if (action_status == LTTNG_ACTION_STATUS_OK) { | |
490 | const char *name; | |
491 | uint64_t max_size; | |
492 | const char *ctrl_url, *data_url; | |
493 | bool starts_with_file, starts_with_net, starts_with_net6; | |
494 | ||
495 | ctrl_url = lttng_snapshot_output_get_ctrl_url(output); | |
496 | assert(ctrl_url && strlen(ctrl_url) > 0); | |
497 | ||
498 | data_url = lttng_snapshot_output_get_data_url(output); | |
499 | assert(data_url); | |
500 | ||
501 | starts_with_file = strncmp(ctrl_url, "file://", strlen("file://")) == 0; | |
502 | starts_with_net = strncmp(ctrl_url, "net://", strlen("net://")) == 0; | |
503 | starts_with_net6 = strncmp(ctrl_url, "net6://", strlen("net6://")) == 0; | |
504 | ||
505 | if (ctrl_url[0] == '/' || starts_with_file) { | |
506 | if (starts_with_file) { | |
507 | ctrl_url += strlen("file://"); | |
508 | } | |
509 | ||
510 | _MSG(", path: %s", ctrl_url); | |
511 | } else if (starts_with_net || starts_with_net6) { | |
512 | _MSG(", url: %s", ctrl_url); | |
513 | } else { | |
514 | assert(strlen(data_url) > 0); | |
515 | ||
516 | _MSG(", control url: %s, data url: %s", ctrl_url, data_url); | |
517 | } | |
518 | ||
519 | name = lttng_snapshot_output_get_name(output); | |
520 | assert(name); | |
521 | if (strlen(name) > 0) { | |
522 | _MSG(", name: %s", name); | |
523 | } | |
524 | ||
525 | max_size = lttng_snapshot_output_get_maxsize(output); | |
526 | if (max_size != -1ULL) { | |
527 | _MSG(", max size: %" PRIu64, max_size); | |
528 | } | |
529 | } | |
530 | ||
531 | MSG(""); | |
532 | break; | |
533 | } | |
534 | ||
535 | default: | |
536 | abort(); | |
537 | } | |
538 | } | |
539 | ||
540 | static | |
541 | void print_one_trigger(const struct lttng_trigger *trigger) | |
542 | { | |
543 | const struct lttng_condition *condition; | |
544 | enum lttng_condition_type condition_type; | |
545 | const struct lttng_action *action; | |
546 | enum lttng_action_type action_type; | |
547 | enum lttng_trigger_status trigger_status; | |
548 | const char *name; | |
549 | enum lttng_trigger_firing_policy firing_policy_type; | |
550 | uint64_t threshold; | |
551 | uid_t trigger_uid; | |
552 | ||
553 | trigger_status = lttng_trigger_get_name(trigger, &name); | |
554 | assert(trigger_status == LTTNG_TRIGGER_STATUS_OK); | |
555 | ||
556 | trigger_status = lttng_trigger_get_owner_uid(trigger, &trigger_uid); | |
557 | assert(trigger_status == LTTNG_TRIGGER_STATUS_OK); | |
558 | ||
559 | MSG("- id: %s", name); | |
560 | MSG(" user id: %d", trigger_uid); | |
561 | ||
562 | trigger_status = lttng_trigger_get_firing_policy( | |
563 | trigger, &firing_policy_type, &threshold); | |
564 | if (trigger_status != LTTNG_TRIGGER_STATUS_OK) { | |
565 | ERR("Failed to get trigger's policy."); | |
566 | goto end; | |
567 | } | |
568 | ||
569 | switch (firing_policy_type) { | |
570 | case LTTNG_TRIGGER_FIRING_POLICY_EVERY_N: | |
571 | if (threshold > 1) { | |
572 | MSG(" firing policy: after every %" PRIu64 " occurences", threshold); | |
573 | } | |
574 | break; | |
575 | case LTTNG_TRIGGER_FIRING_POLICY_ONCE_AFTER_N: | |
576 | MSG(" firing policy: once after %" PRIu64 " occurences", threshold); | |
577 | break; | |
578 | default: | |
579 | abort(); | |
580 | } | |
581 | ||
582 | condition = lttng_trigger_get_const_condition(trigger); | |
583 | condition_type = lttng_condition_get_type(condition); | |
584 | MSG(" condition: %s", lttng_condition_type_str(condition_type)); | |
585 | switch (condition_type) { | |
d602bd6a JR |
586 | case LTTNG_CONDITION_TYPE_ON_EVENT: |
587 | print_condition_on_event(condition); | |
0de2479d SM |
588 | break; |
589 | default: | |
590 | MSG(" (condition type not handled in %s)", __func__); | |
591 | break; | |
592 | } | |
593 | ||
594 | action = lttng_trigger_get_const_action(trigger); | |
595 | action_type = lttng_action_get_type(action); | |
596 | if (action_type == LTTNG_ACTION_TYPE_GROUP) { | |
597 | unsigned int count, i; | |
598 | enum lttng_action_status action_status; | |
599 | ||
600 | MSG(" actions:"); | |
601 | ||
602 | action_status = lttng_action_group_get_count(action, &count); | |
603 | assert(action_status == LTTNG_ACTION_STATUS_OK); | |
604 | ||
605 | for (i = 0; i < count; i++) { | |
606 | const struct lttng_action *subaction = | |
607 | lttng_action_group_get_at_index( | |
608 | action, i); | |
609 | ||
610 | _MSG(" "); | |
611 | print_one_action(subaction); | |
612 | } | |
613 | } else { | |
614 | _MSG(" action:"); | |
615 | print_one_action(action); | |
616 | } | |
617 | ||
618 | end: | |
619 | return; | |
620 | } | |
621 | ||
622 | static | |
623 | int compare_triggers_by_name(const void *a, const void *b) | |
624 | { | |
625 | const struct lttng_trigger *trigger_a = *((const struct lttng_trigger **) a); | |
626 | const struct lttng_trigger *trigger_b = *((const struct lttng_trigger **) b); | |
627 | const char *name_a, *name_b; | |
628 | enum lttng_trigger_status trigger_status; | |
629 | ||
630 | trigger_status = lttng_trigger_get_name(trigger_a, &name_a); | |
631 | assert(trigger_status == LTTNG_TRIGGER_STATUS_OK); | |
632 | ||
633 | trigger_status = lttng_trigger_get_name(trigger_b, &name_b); | |
634 | assert(trigger_status == LTTNG_TRIGGER_STATUS_OK); | |
635 | ||
636 | return strcmp(name_a, name_b); | |
637 | } | |
638 | ||
639 | int cmd_list_triggers(int argc, const char **argv) | |
640 | { | |
641 | int ret; | |
642 | struct argpar_parse_ret argpar_parse_ret = {}; | |
643 | struct lttng_triggers *triggers = NULL; | |
644 | int i; | |
645 | struct lttng_dynamic_pointer_array sorted_triggers; | |
646 | enum lttng_trigger_status trigger_status; | |
647 | unsigned int num_triggers; | |
648 | ||
649 | lttng_dynamic_pointer_array_init(&sorted_triggers, NULL); | |
650 | ||
651 | argpar_parse_ret = argpar_parse( | |
652 | argc - 1, argv + 1, list_trigger_options, true); | |
653 | if (!argpar_parse_ret.items) { | |
654 | ERR("%s", argpar_parse_ret.error); | |
655 | goto error; | |
656 | } | |
657 | ||
658 | for (i = 0; i < argpar_parse_ret.items->n_items; i++) { | |
659 | const struct argpar_item *item = | |
660 | argpar_parse_ret.items->items[i]; | |
661 | ||
662 | if (item->type == ARGPAR_ITEM_TYPE_OPT) { | |
663 | const struct argpar_item_opt *item_opt = | |
664 | (const struct argpar_item_opt *) item; | |
665 | ||
666 | switch (item_opt->descr->id) { | |
667 | case OPT_HELP: | |
668 | SHOW_HELP(); | |
669 | ret = 0; | |
670 | goto end; | |
671 | ||
672 | case OPT_LIST_OPTIONS: | |
673 | list_cmd_options_argpar(stdout, | |
674 | list_trigger_options); | |
675 | ret = 0; | |
676 | goto end; | |
677 | ||
678 | default: | |
679 | abort(); | |
680 | } | |
681 | ||
682 | } else { | |
683 | const struct argpar_item_non_opt *item_non_opt = | |
684 | (const struct argpar_item_non_opt *) item; | |
685 | ||
686 | ERR("Unexpected argument: %s", item_non_opt->arg); | |
687 | } | |
688 | } | |
689 | ||
690 | ret = lttng_list_triggers(&triggers); | |
691 | if (ret != LTTNG_OK) { | |
692 | ERR("Error listing triggers: %s.", lttng_strerror(-ret)); | |
693 | goto error; | |
694 | } | |
695 | ||
696 | trigger_status = lttng_triggers_get_count(triggers, &num_triggers); | |
697 | if (trigger_status != LTTNG_TRIGGER_STATUS_OK) { | |
698 | ERR("Failed to get trigger count."); | |
699 | goto error; | |
700 | } | |
701 | ||
702 | for (i = 0; i < num_triggers; i++) { | |
703 | const int add_ret = lttng_dynamic_pointer_array_add_pointer( | |
704 | &sorted_triggers, | |
705 | (void *) lttng_triggers_get_at_index(triggers, i)); | |
706 | ||
707 | if (add_ret) { | |
708 | ERR("Failed to allocate array of struct lttng_trigger *."); | |
709 | goto error; | |
710 | } | |
711 | } | |
712 | ||
713 | qsort(sorted_triggers.array.buffer.data, num_triggers, | |
714 | sizeof(struct lttng_trigger *), | |
715 | compare_triggers_by_name); | |
716 | ||
717 | for (i = 0; i < num_triggers; i++) { | |
718 | const struct lttng_trigger *trigger_to_print = | |
719 | (const struct lttng_trigger *) | |
720 | lttng_dynamic_pointer_array_get_pointer( | |
721 | &sorted_triggers, i); | |
722 | ||
723 | print_one_trigger(trigger_to_print); | |
724 | } | |
725 | ||
726 | ret = 0; | |
727 | goto end; | |
728 | ||
729 | error: | |
730 | ret = 1; | |
731 | ||
732 | end: | |
733 | argpar_parse_ret_fini(&argpar_parse_ret); | |
734 | lttng_triggers_destroy(triggers); | |
735 | lttng_dynamic_pointer_array_reset(&sorted_triggers); | |
736 | ||
737 | return ret; | |
738 | } |