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