7803fd51dac96eca02d4b05a9f56bc3c6f152ae0
[lttng-tools.git] / tests / regression / tools / trigger / utils / notification-client.c
1 /*
2 * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 */
7
8 #include <getopt.h>
9 #include <stdbool.h>
10 #include <stddef.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/time.h>
15 #include <time.h>
16
17 #include <lttng/condition/on-event.h>
18 #include <lttng/lttng.h>
19
20 #include "utils.h"
21
22 static struct option long_options[] =
23 {
24 /* These options set a flag. */
25 {"trigger", required_argument, 0, 't'},
26 {"sync-after-notif-register", required_argument, 0, 'a'},
27 {0, 0, 0, 0}
28 };
29
30 static bool action_group_contains_notify(
31 const struct lttng_action *action_group)
32 {
33 unsigned int i, count;
34 enum lttng_action_status status =
35 lttng_action_group_get_count(action_group, &count);
36
37 if (status != LTTNG_ACTION_STATUS_OK) {
38 printf("Failed to get action count from action group\n");
39 exit(1);
40 }
41
42 for (i = 0; i < count; i++) {
43 const struct lttng_action *action =
44 lttng_action_group_get_at_index(
45 action_group, i);
46 const enum lttng_action_type action_type =
47 lttng_action_get_type(action);
48
49 if (action_type == LTTNG_ACTION_TYPE_NOTIFY) {
50 return true;
51 }
52 }
53 return false;
54 }
55
56 static bool is_trigger_name(const char *expected_trigger_name,
57 struct lttng_notification *notification)
58 {
59 const char *trigger_name = NULL;
60 enum lttng_trigger_status trigger_status;
61 const struct lttng_trigger *trigger;
62 bool names_match;
63
64 trigger = lttng_notification_get_trigger(notification);
65 if (!trigger) {
66 fprintf(stderr, "Failed to get trigger from notification\n");
67 names_match = false;
68 goto end;
69 }
70
71 trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
72 if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
73 fprintf(stderr, "Failed to get name from notification's trigger\n");
74 names_match = false;
75 goto end;
76 }
77
78 names_match = strcmp(expected_trigger_name, trigger_name) == 0;
79 if (!names_match) {
80 fprintf(stderr, "Got an unexpected trigger name: name = '%s', expected name = '%s'\n",
81 trigger_name, expected_trigger_name);
82 }
83 end:
84 return names_match;
85 }
86
87 int main(int argc, char **argv)
88 {
89 int ret;
90 int option;
91 int option_index;
92 const char *expected_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
99 while ((option = getopt_long(argc, argv, "a:t:",
100 long_options, &option_index)) != -1) {
101 switch (option) {
102 case 'a':
103 after_notif_register_file_path = strdup(optarg);
104 break;
105 case 't':
106 expected_trigger_name = strdup(optarg);
107 break;
108 case '?':
109 /* getopt_long already printed an error message. */
110 default:
111 ret = -1;
112 goto end;
113 }
114 }
115
116 if (optind != argc) {
117 ret = -1;
118 goto end;
119 }
120
121
122 notification_channel = lttng_notification_channel_create(
123 lttng_session_daemon_notification_endpoint);
124 if (!notification_channel) {
125 fprintf(stderr, "Failed to create notification channel\n");
126 ret = -1;
127 goto end;
128 }
129
130 ret = lttng_list_triggers(&triggers);
131 if (ret != LTTNG_OK) {
132 fprintf(stderr, "Failed to list triggers\n");
133 ret = -1;
134 goto end;
135 }
136
137 trigger_status = lttng_triggers_get_count(triggers, &count);
138 if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
139 fprintf(stderr, "Failed to get trigger count\n");
140 ret = -1;
141 goto end;
142 }
143
144 /* Look for the trigger we want to subscribe to. */
145 for (i = 0; i < count; i++) {
146 const struct lttng_trigger *trigger =
147 lttng_triggers_get_at_index(triggers, i);
148 const struct lttng_condition *condition =
149 lttng_trigger_get_const_condition(trigger);
150 const struct lttng_action *action =
151 lttng_trigger_get_const_action(trigger);
152 const enum lttng_action_type action_type =
153 lttng_action_get_type(action);
154 enum lttng_notification_channel_status channel_status;
155 const char *trigger_name = NULL;
156
157 lttng_trigger_get_name(trigger, &trigger_name);
158 if (strcmp(trigger_name, expected_trigger_name)) {
159 continue;
160 }
161
162 if (!((action_type == LTTNG_ACTION_TYPE_GROUP &&
163 action_group_contains_notify(action)) ||
164 action_type == LTTNG_ACTION_TYPE_NOTIFY)) {
165 /* "The action of trigger is not notify, skipping. */
166 continue;
167 }
168
169 channel_status = lttng_notification_channel_subscribe(
170 notification_channel, condition);
171 if (channel_status) {
172 fprintf(stderr, "Failed to subscribe to notifications of trigger \"%s\"\n",
173 trigger_name);
174 ret = -1;
175 goto end;
176 }
177
178 subcription_count++;
179 }
180
181 if (subcription_count == 0) {
182 printf("No matching trigger with a notify action found.\n");
183 ret = 0;
184 goto end;
185 }
186
187
188 /*
189 * We registered to the notification of our target trigger. We can now
190 * create the sync file to signify that we are ready.
191 */
192 ret = create_file(after_notif_register_file_path);
193 if (ret != 0) {
194 goto end;
195 }
196
197 for (;;) {
198 struct lttng_notification *notification;
199 enum lttng_notification_channel_status channel_status;
200
201 channel_status =
202 lttng_notification_channel_get_next_notification(
203 notification_channel,
204 &notification);
205 switch (channel_status) {
206 case LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED:
207 printf("Dropped notification\n");
208 ret = -1;
209 goto end;
210 case LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED:
211 ret = -1;
212 goto end;
213 case LTTNG_NOTIFICATION_CHANNEL_STATUS_OK:
214 break;
215 case LTTNG_NOTIFICATION_CHANNEL_STATUS_CLOSED:
216 printf("Notification channel was closed by peer.\n");
217 ret = -1;
218 break;
219 default:
220 fprintf(stderr, "A communication error occurred on the notification channel.\n");
221 ret = -1;
222 goto end;
223 }
224
225 ret = is_trigger_name(expected_trigger_name, notification);
226 lttng_notification_destroy(notification);
227 if (!ret) {
228 ret = -1;
229 goto end;
230 } else {
231 ret = 0;
232 goto end;
233 }
234 }
235 end:
236 lttng_triggers_destroy(triggers);
237 lttng_notification_channel_destroy(notification_channel);
238 return !!ret;
239 }
This page took 0.049271 seconds and 3 git commands to generate.