2 * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 * SPDX-License-Identifier: MIT
10 #include <lttng/action/list-internal.hpp>
11 #include <lttng/condition/event-rule-matches.h>
12 #include <lttng/lttng.h>
23 static struct option long_options
[] = {
24 /* These options set a flag. */
25 { "trigger", required_argument
, 0, 't' },
26 { "sync-after-notif-register", required_argument
, 0, 'a' },
27 /* Default alue for count is 1 */
28 { "count", required_argument
, 0, 'b' },
30 * When end-trigger is present the reception loop is exited only when a
31 * notification matching the end trigger is received.
32 * Otherwise the loop is exited when the count of notification received
33 * for `trigger` math the `count` argument.
35 { "end-trigger", required_argument
, 0, 'c' },
39 static bool action_list_contains_notify(const struct lttng_action
*action_list
)
41 const struct lttng_action
*sub_action
;
43 for_each_action_const (sub_action
, action_list
) {
44 if (lttng_action_get_type(sub_action
) == LTTNG_ACTION_TYPE_NOTIFY
) {
51 /* Only expects named triggers. */
52 static bool is_trigger_name(const char *expected_trigger_name
,
53 struct lttng_notification
*notification
)
55 const char *trigger_name
= NULL
;
56 enum lttng_trigger_status trigger_status
;
57 const struct lttng_trigger
*trigger
;
60 trigger
= lttng_notification_get_trigger(notification
);
62 fprintf(stderr
, "Failed to get trigger from notification\n");
67 trigger_status
= lttng_trigger_get_name(trigger
, &trigger_name
);
68 if (trigger_status
!= LTTNG_TRIGGER_STATUS_OK
) {
69 fprintf(stderr
, "Failed to get name from notification's trigger\n");
74 names_match
= strcmp(expected_trigger_name
, trigger_name
) == 0;
77 "Got an unexpected trigger name: name = '%s', expected name = '%s'\n",
79 expected_trigger_name
);
85 int main(int argc
, char **argv
)
90 char *expected_trigger_name
= NULL
;
91 char *end_trigger_name
= NULL
;
92 struct lttng_triggers
*triggers
= NULL
;
93 unsigned int count
, i
, subcription_count
= 0;
94 enum lttng_trigger_status trigger_status
;
95 char *after_notif_register_file_path
= NULL
;
96 struct lttng_notification_channel
*notification_channel
= NULL
;
97 int expected_notifications
= 1, notification_count
= 0;
99 while ((option
= getopt_long(argc
, argv
, "a:b:c:t:", long_options
, &option_index
)) != -1) {
102 after_notif_register_file_path
= strdup(optarg
);
105 expected_notifications
= atoi(optarg
);
108 end_trigger_name
= strdup(optarg
);
111 expected_trigger_name
= strdup(optarg
);
114 /* getopt_long already printed an error message. */
121 if (optind
!= argc
) {
126 notification_channel
=
127 lttng_notification_channel_create(lttng_session_daemon_notification_endpoint
);
128 if (!notification_channel
) {
129 fprintf(stderr
, "Failed to create notification channel\n");
134 ret
= lttng_list_triggers(&triggers
);
135 if (ret
!= LTTNG_OK
) {
136 fprintf(stderr
, "Failed to list triggers\n");
141 trigger_status
= lttng_triggers_get_count(triggers
, &count
);
142 if (trigger_status
!= LTTNG_TRIGGER_STATUS_OK
) {
143 fprintf(stderr
, "Failed to get trigger count\n");
148 /* Look for the trigger we want to subscribe to. */
149 for (i
= 0; i
< count
; i
++) {
150 const struct lttng_trigger
*trigger
= lttng_triggers_get_at_index(triggers
, i
);
151 const struct lttng_condition
*condition
=
152 lttng_trigger_get_const_condition(trigger
);
153 const struct lttng_action
*action
= lttng_trigger_get_const_action(trigger
);
154 const enum lttng_action_type action_type
= lttng_action_get_type(action
);
155 enum lttng_notification_channel_status channel_status
;
156 const char *trigger_name
= NULL
;
158 lttng_trigger_get_name(trigger
, &trigger_name
);
159 if (strcmp(trigger_name
, expected_trigger_name
) != 0) {
160 /* Might match the end event trigger */
161 if (end_trigger_name
!= NULL
&&
162 strcmp(trigger_name
, end_trigger_name
) != 0) {
166 if (!((action_type
== LTTNG_ACTION_TYPE_LIST
&&
167 action_list_contains_notify(action
)) ||
168 action_type
== LTTNG_ACTION_TYPE_NOTIFY
)) {
169 /* "The action of trigger is not notify, skipping. */
174 lttng_notification_channel_subscribe(notification_channel
, condition
);
175 if (channel_status
) {
177 "Failed to subscribe to notifications of trigger \"%s\"\n",
186 if (subcription_count
== 0) {
187 fprintf(stderr
, "No matching trigger with a notify action found.\n");
192 if (end_trigger_name
!= NULL
&& subcription_count
!= 2) {
193 fprintf(stderr
, "No matching end event trigger with a notify action found.\n");
199 * We registered to the notification of our target trigger. We can now
200 * create the sync file to signify that we are ready.
202 ret
= create_file(after_notif_register_file_path
);
208 struct lttng_notification
*notification
;
209 enum lttng_notification_channel_status channel_status
;
211 channel_status
= lttng_notification_channel_get_next_notification(
212 notification_channel
, ¬ification
);
213 switch (channel_status
) {
214 case LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED
:
215 printf("Dropped notification\n");
218 case LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED
:
221 case LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
:
223 case LTTNG_NOTIFICATION_CHANNEL_STATUS_CLOSED
:
224 printf("Notification channel was closed by peer.\n");
228 "A communication error occurred on the notification channel.\n");
233 /* Early exit check. */
234 if (end_trigger_name
!= NULL
&& is_trigger_name(end_trigger_name
, notification
)) {
235 /* Exit the loop immediately. */
236 printf("Received end event notification from trigger %s\n",
238 lttng_notification_destroy(notification
);
239 goto evaluate_success
;
242 ret
= is_trigger_name(expected_trigger_name
, notification
);
243 lttng_notification_destroy(notification
);
249 printf("Received event notification from trigger %s\n", expected_trigger_name
);
250 notification_count
++;
251 if (end_trigger_name
== NULL
&& expected_notifications
== notification_count
) {
253 * Here the loop exit is controlled by the number of
254 * notification and not by the reception of the end
255 * event trigger notification. This represent the
259 goto evaluate_success
;
264 if (expected_notifications
== notification_count
) {
269 "Expected %d notification got %d\n",
270 expected_notifications
,
276 lttng_triggers_destroy(triggers
);
277 lttng_notification_channel_destroy(notification_channel
);
278 free(after_notif_register_file_path
);
279 free(end_trigger_name
);
280 free(expected_trigger_name
);