2 * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 * SPDX-License-Identifier: MIT
10 #include <common/error.hpp>
12 #include <lttng/action/list-internal.hpp>
13 #include <lttng/condition/event-rule-matches.h>
14 #include <lttng/lttng.h>
25 static struct option long_options
[] = {
26 /* These options set a flag. */
27 { "trigger", required_argument
, 0, 't' },
28 { "sync-after-notif-register", required_argument
, 0, 'a' },
29 /* Default alue for count is 1 */
30 { "count", required_argument
, 0, 'b' },
32 * When end-trigger is present the reception loop is exited only when a
33 * notification matching the end trigger is received.
34 * Otherwise the loop is exited when the count of notification received
35 * for `trigger` math the `count` argument.
37 { "end-trigger", required_argument
, 0, 'c' },
41 static bool action_list_contains_notify(const struct lttng_action
*action_list
)
43 for (auto sub_action
: lttng::ctl::const_action_list_view(action_list
)) {
44 if (lttng_action_get_type(sub_action
) == LTTNG_ACTION_TYPE_NOTIFY
) {
52 /* Only expects named triggers. */
53 static bool is_trigger_name(const char *expected_trigger_name
,
54 struct lttng_notification
*notification
)
56 const char *trigger_name
= NULL
;
57 enum lttng_trigger_status trigger_status
;
58 const struct lttng_trigger
*trigger
;
61 trigger
= lttng_notification_get_trigger(notification
);
63 fprintf(stderr
, "Failed to get trigger from notification\n");
68 trigger_status
= lttng_trigger_get_name(trigger
, &trigger_name
);
69 if (trigger_status
!= LTTNG_TRIGGER_STATUS_OK
) {
70 fprintf(stderr
, "Failed to get name from notification's trigger\n");
75 names_match
= strcmp(expected_trigger_name
, trigger_name
) == 0;
78 "Got an unexpected trigger name: name = '%s', expected name = '%s'\n",
80 expected_trigger_name
);
86 static int _main(int argc
, char **argv
)
91 char *expected_trigger_name
= NULL
;
92 char *end_trigger_name
= NULL
;
93 struct lttng_triggers
*triggers
= NULL
;
94 unsigned int count
, i
, subcription_count
= 0;
95 enum lttng_trigger_status trigger_status
;
96 char *after_notif_register_file_path
= NULL
;
97 struct lttng_notification_channel
*notification_channel
= NULL
;
98 int expected_notifications
= 1, notification_count
= 0;
100 while ((option
= getopt_long(argc
, argv
, "a:b:c:t:", long_options
, &option_index
)) != -1) {
103 after_notif_register_file_path
= strdup(optarg
);
106 expected_notifications
= atoi(optarg
);
109 end_trigger_name
= strdup(optarg
);
112 expected_trigger_name
= strdup(optarg
);
115 /* getopt_long already printed an error message. */
122 if (optind
!= argc
) {
127 notification_channel
=
128 lttng_notification_channel_create(lttng_session_daemon_notification_endpoint
);
129 if (!notification_channel
) {
130 fprintf(stderr
, "Failed to create notification channel\n");
135 ret
= lttng_list_triggers(&triggers
);
136 if (ret
!= LTTNG_OK
) {
137 fprintf(stderr
, "Failed to list triggers\n");
142 trigger_status
= lttng_triggers_get_count(triggers
, &count
);
143 if (trigger_status
!= LTTNG_TRIGGER_STATUS_OK
) {
144 fprintf(stderr
, "Failed to get trigger count\n");
149 /* Look for the trigger we want to subscribe to. */
150 for (i
= 0; i
< count
; i
++) {
151 const struct lttng_trigger
*trigger
= lttng_triggers_get_at_index(triggers
, i
);
152 const struct lttng_condition
*condition
=
153 lttng_trigger_get_const_condition(trigger
);
154 const struct lttng_action
*action
= lttng_trigger_get_const_action(trigger
);
155 const enum lttng_action_type action_type
= lttng_action_get_type(action
);
156 enum lttng_notification_channel_status channel_status
;
157 const char *trigger_name
= NULL
;
159 lttng_trigger_get_name(trigger
, &trigger_name
);
160 if (strcmp(trigger_name
, expected_trigger_name
) != 0) {
161 /* Might match the end event trigger */
162 if (end_trigger_name
!= NULL
&&
163 strcmp(trigger_name
, end_trigger_name
) != 0) {
167 if (!((action_type
== LTTNG_ACTION_TYPE_LIST
&&
168 action_list_contains_notify(action
)) ||
169 action_type
== LTTNG_ACTION_TYPE_NOTIFY
)) {
170 /* "The action of trigger is not notify, skipping. */
175 lttng_notification_channel_subscribe(notification_channel
, condition
);
176 if (channel_status
) {
178 "Failed to subscribe to notifications of trigger \"%s\"\n",
187 if (subcription_count
== 0) {
188 fprintf(stderr
, "No matching trigger with a notify action found.\n");
193 if (end_trigger_name
!= NULL
&& subcription_count
!= 2) {
194 fprintf(stderr
, "No matching end event trigger with a notify action found.\n");
200 * We registered to the notification of our target trigger. We can now
201 * create the sync file to signify that we are ready.
203 ret
= create_file(after_notif_register_file_path
);
209 struct lttng_notification
*notification
;
210 enum lttng_notification_channel_status channel_status
;
212 channel_status
= lttng_notification_channel_get_next_notification(
213 notification_channel
, ¬ification
);
214 switch (channel_status
) {
215 case LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED
:
216 printf("Dropped notification\n");
219 case LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED
:
222 case LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
:
224 case LTTNG_NOTIFICATION_CHANNEL_STATUS_CLOSED
:
225 printf("Notification channel was closed by peer.\n");
229 "A communication error occurred on the notification channel.\n");
234 /* Early exit check. */
235 if (end_trigger_name
!= NULL
&& is_trigger_name(end_trigger_name
, notification
)) {
236 /* Exit the loop immediately. */
237 printf("Received end event notification from trigger %s\n",
239 lttng_notification_destroy(notification
);
240 goto evaluate_success
;
243 ret
= is_trigger_name(expected_trigger_name
, notification
);
244 lttng_notification_destroy(notification
);
250 printf("Received event notification from trigger %s\n", expected_trigger_name
);
251 notification_count
++;
252 if (end_trigger_name
== NULL
&& expected_notifications
== notification_count
) {
254 * Here the loop exit is controlled by the number of
255 * notification and not by the reception of the end
256 * event trigger notification. This represent the
260 goto evaluate_success
;
265 if (expected_notifications
== notification_count
) {
270 "Expected %d notification got %d\n",
271 expected_notifications
,
277 lttng_triggers_destroy(triggers
);
278 lttng_notification_channel_destroy(notification_channel
);
279 free(after_notif_register_file_path
);
280 free(end_trigger_name
);
281 free(expected_trigger_name
);
285 int main(int argc
, char **argv
)
288 return _main(argc
, argv
);
289 } catch (const std::exception
& e
) {
290 ERR_FMT("Unhandled exception caught by notification client: %s", e
.what());