Fix: erroneous specifier used with ERR_FMT macro
[lttng-tools.git] / tests / regression / tools / trigger / utils / notification-client.cpp
CommitLineData
6ba31891
FD
1/*
2 * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 */
7
28f23191
JG
8#include "utils.h"
9
d5ed3e6f
JG
10#include <common/error.hpp>
11
2460203a 12#include <lttng/action/list-internal.hpp>
28f23191
JG
13#include <lttng/condition/event-rule-matches.h>
14#include <lttng/lttng.h>
15
6ba31891
FD
16#include <getopt.h>
17#include <stdbool.h>
18#include <stddef.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <sys/time.h>
23#include <time.h>
24
28f23191 25static struct option long_options[] = {
6ba31891 26 /* These options set a flag. */
28f23191
JG
27 { "trigger", required_argument, 0, 't' },
28 { "sync-after-notif-register", required_argument, 0, 'a' },
6ffce1f5 29 /* Default alue for count is 1 */
28f23191 30 { "count", required_argument, 0, 'b' },
6ffce1f5
JR
31 /*
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.
36 */
28f23191
JG
37 { "end-trigger", required_argument, 0, 'c' },
38 { 0, 0, 0, 0 }
6ba31891
FD
39};
40
28f23191 41static bool action_list_contains_notify(const struct lttng_action *action_list)
6ba31891 42{
b17ed2ad 43 for (auto sub_action : lttng::ctl::const_action_list_view(action_list)) {
2460203a 44 if (lttng_action_get_type(sub_action) == LTTNG_ACTION_TYPE_NOTIFY) {
6ba31891
FD
45 return true;
46 }
47 }
b17ed2ad 48
6ba31891
FD
49 return false;
50}
51
0efb2ad7 52/* Only expects named triggers. */
7d59def2 53static bool is_trigger_name(const char *expected_trigger_name,
28f23191 54 struct lttng_notification *notification)
6ba31891 55{
65f64978
JG
56 const char *trigger_name = NULL;
57 enum lttng_trigger_status trigger_status;
58 const struct lttng_trigger *trigger;
59 bool names_match;
6ba31891 60
65f64978
JG
61 trigger = lttng_notification_get_trigger(notification);
62 if (!trigger) {
63 fprintf(stderr, "Failed to get trigger from notification\n");
64 names_match = false;
65 goto end;
6ba31891 66 }
65f64978
JG
67
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");
71 names_match = false;
72 goto end;
6ba31891
FD
73 }
74
65f64978 75 names_match = strcmp(expected_trigger_name, trigger_name) == 0;
7d59def2 76 if (!names_match) {
28f23191
JG
77 fprintf(stderr,
78 "Got an unexpected trigger name: name = '%s', expected name = '%s'\n",
79 trigger_name,
80 expected_trigger_name);
7d59def2 81 }
65f64978
JG
82end:
83 return names_match;
6ba31891
FD
84}
85
d5ed3e6f 86static int _main(int argc, char **argv)
6ba31891
FD
87{
88 int ret;
89 int option;
90 int option_index;
3e68c9e8
JG
91 char *expected_trigger_name = NULL;
92 char *end_trigger_name = NULL;
6ba31891
FD
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;
6ffce1f5 98 int expected_notifications = 1, notification_count = 0;
6ba31891 99
28f23191 100 while ((option = getopt_long(argc, argv, "a:b:c:t:", long_options, &option_index)) != -1) {
6ba31891
FD
101 switch (option) {
102 case 'a':
103 after_notif_register_file_path = strdup(optarg);
104 break;
6ffce1f5
JR
105 case 'b':
106 expected_notifications = atoi(optarg);
107 break;
108 case 'c':
109 end_trigger_name = strdup(optarg);
110 break;
6ba31891
FD
111 case 't':
112 expected_trigger_name = strdup(optarg);
113 break;
114 case '?':
115 /* getopt_long already printed an error message. */
116 default:
117 ret = -1;
118 goto end;
119 }
120 }
121
122 if (optind != argc) {
123 ret = -1;
124 goto end;
125 }
126
28f23191
JG
127 notification_channel =
128 lttng_notification_channel_create(lttng_session_daemon_notification_endpoint);
6ba31891
FD
129 if (!notification_channel) {
130 fprintf(stderr, "Failed to create notification channel\n");
131 ret = -1;
132 goto end;
133 }
134
135 ret = lttng_list_triggers(&triggers);
136 if (ret != LTTNG_OK) {
137 fprintf(stderr, "Failed to list triggers\n");
7d59def2 138 ret = -1;
6ba31891
FD
139 goto end;
140 }
141
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");
145 ret = -1;
146 goto end;
147 }
148
7d59def2 149 /* Look for the trigger we want to subscribe to. */
6ba31891 150 for (i = 0; i < count; i++) {
28f23191 151 const struct lttng_trigger *trigger = lttng_triggers_get_at_index(triggers, i);
6ba31891 152 const struct lttng_condition *condition =
28f23191
JG
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);
6ba31891
FD
156 enum lttng_notification_channel_status channel_status;
157 const char *trigger_name = NULL;
158
159 lttng_trigger_get_name(trigger, &trigger_name);
5c7248cd 160 if (strcmp(trigger_name, expected_trigger_name) != 0) {
6ffce1f5
JR
161 /* Might match the end event trigger */
162 if (end_trigger_name != NULL &&
28f23191 163 strcmp(trigger_name, end_trigger_name) != 0) {
6ffce1f5
JR
164 continue;
165 }
6ba31891 166 }
7c2fae7c 167 if (!((action_type == LTTNG_ACTION_TYPE_LIST &&
28f23191
JG
168 action_list_contains_notify(action)) ||
169 action_type == LTTNG_ACTION_TYPE_NOTIFY)) {
6ba31891
FD
170 /* "The action of trigger is not notify, skipping. */
171 continue;
172 }
173
28f23191
JG
174 channel_status =
175 lttng_notification_channel_subscribe(notification_channel, condition);
6ba31891 176 if (channel_status) {
28f23191
JG
177 fprintf(stderr,
178 "Failed to subscribe to notifications of trigger \"%s\"\n",
179 trigger_name);
6ba31891
FD
180 ret = -1;
181 goto end;
182 }
183
184 subcription_count++;
185 }
186
187 if (subcription_count == 0) {
6ffce1f5
JR
188 fprintf(stderr, "No matching trigger with a notify action found.\n");
189 ret = -1;
6ba31891
FD
190 goto end;
191 }
192
6ffce1f5
JR
193 if (end_trigger_name != NULL && subcription_count != 2) {
194 fprintf(stderr, "No matching end event trigger with a notify action found.\n");
195 ret = -1;
196 goto end;
197 }
6ba31891
FD
198
199 /*
200 * We registered to the notification of our target trigger. We can now
201 * create the sync file to signify that we are ready.
202 */
203 ret = create_file(after_notif_register_file_path);
204 if (ret != 0) {
205 goto end;
206 }
207
208 for (;;) {
209 struct lttng_notification *notification;
210 enum lttng_notification_channel_status channel_status;
211
28f23191
JG
212 channel_status = lttng_notification_channel_get_next_notification(
213 notification_channel, &notification);
6ba31891
FD
214 switch (channel_status) {
215 case LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED:
216 printf("Dropped notification\n");
7d59def2
JR
217 ret = -1;
218 goto end;
6ba31891 219 case LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED:
7d59def2 220 ret = -1;
6ba31891
FD
221 goto end;
222 case LTTNG_NOTIFICATION_CHANNEL_STATUS_OK:
223 break;
224 case LTTNG_NOTIFICATION_CHANNEL_STATUS_CLOSED:
225 printf("Notification channel was closed by peer.\n");
226 break;
227 default:
28f23191
JG
228 fprintf(stderr,
229 "A communication error occurred on the notification channel.\n");
6ba31891
FD
230 ret = -1;
231 goto end;
232 }
233
6ffce1f5 234 /* Early exit check. */
28f23191 235 if (end_trigger_name != NULL && is_trigger_name(end_trigger_name, notification)) {
6ffce1f5
JR
236 /* Exit the loop immediately. */
237 printf("Received end event notification from trigger %s\n",
28f23191 238 end_trigger_name);
6ffce1f5
JR
239 lttng_notification_destroy(notification);
240 goto evaluate_success;
241 }
242
7d59def2 243 ret = is_trigger_name(expected_trigger_name, notification);
6ba31891 244 lttng_notification_destroy(notification);
7d59def2
JR
245 if (!ret) {
246 ret = -1;
247 goto end;
6ffce1f5
JR
248 }
249
28f23191 250 printf("Received event notification from trigger %s\n", expected_trigger_name);
6ffce1f5 251 notification_count++;
28f23191 252 if (end_trigger_name == NULL && expected_notifications == notification_count) {
6ffce1f5
JR
253 /*
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
257 * default behavior.
258 *
259 */
260 goto evaluate_success;
6ba31891
FD
261 }
262 }
6ffce1f5
JR
263
264evaluate_success:
265 if (expected_notifications == notification_count) {
266 /* Success */
267 ret = 0;
268 } else {
28f23191
JG
269 fprintf(stderr,
270 "Expected %d notification got %d\n",
271 expected_notifications,
272 notification_count);
6ffce1f5
JR
273 ret = 1;
274 }
275
6ba31891
FD
276end:
277 lttng_triggers_destroy(triggers);
278 lttng_notification_channel_destroy(notification_channel);
3e68c9e8
JG
279 free(after_notif_register_file_path);
280 free(end_trigger_name);
281 free(expected_trigger_name);
6ba31891
FD
282 return !!ret;
283}
d5ed3e6f
JG
284
285int main(int argc, char **argv)
286{
287 try {
288 return _main(argc, argv);
289 } catch (const std::exception& e) {
ae26b182 290 ERR_FMT("Unhandled exception caught by notification client: {}", e.what());
d5ed3e6f
JG
291 abort();
292 }
293}
This page took 0.056345 seconds and 4 git commands to generate.