Run clang-format on the whole tree
[lttng-tools.git] / src / lib / lttng-ctl / lttng-ctl-health.cpp
1 /*
2 * lttng-ctl-health.c
3 *
4 * Linux Trace Toolkit Health Control Library
5 *
6 * Copyright (C) 2011 EfficiOS Inc.
7 * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8 *
9 * SPDX-License-Identifier: LGPL-2.1-only
10 *
11 */
12
13 #define _LGPL_SOURCE
14 #include "lttng-ctl-helper.hpp"
15
16 #include <common/compat/errno.hpp>
17 #include <common/defaults.hpp>
18 #include <common/utils.hpp>
19
20 #include <lttng/health-internal.hpp>
21
22 #include <bin/lttng-consumerd/health-consumerd.hpp>
23 #include <bin/lttng-relayd/health-relayd.hpp>
24 #include <bin/lttng-sessiond/health-sessiond.hpp>
25 #include <limits.h>
26 #include <stdint.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30
31 enum health_component {
32 HEALTH_COMPONENT_SESSIOND,
33 HEALTH_COMPONENT_CONSUMERD,
34 HEALTH_COMPONENT_RELAYD,
35
36 NR_HEALTH_COMPONENT,
37 };
38
39 struct lttng_health_thread {
40 struct lttng_health *p;
41 int state;
42 };
43
44 struct lttng_health {
45 enum health_component component;
46 uint64_t state;
47 unsigned int nr_threads;
48 char health_sock_path[PATH_MAX];
49 /* For consumer health only */
50 enum lttng_health_consumerd consumerd_type;
51 struct lttng_health_thread thread[];
52 };
53
54 static const char *get_sessiond_thread_name(health_type_sessiond type)
55 {
56 switch (type) {
57 case HEALTH_SESSIOND_TYPE_CMD:
58 return "Session daemon command";
59 case HEALTH_SESSIOND_TYPE_APP_MANAGE:
60 return "Session daemon application manager";
61 case HEALTH_SESSIOND_TYPE_APP_REG:
62 return "Session daemon application registration";
63 case HEALTH_SESSIOND_TYPE_KERNEL:
64 return "Session daemon kernel";
65 case HEALTH_SESSIOND_TYPE_CONSUMER:
66 return "Session daemon consumer manager";
67 case HEALTH_SESSIOND_TYPE_APP_MANAGE_NOTIFY:
68 return "Session daemon application notification manager";
69 case HEALTH_SESSIOND_TYPE_APP_REG_DISPATCH:
70 return "Session daemon application registration dispatcher";
71 case HEALTH_SESSIOND_TYPE_NOTIFICATION:
72 return "Session daemon notification";
73 case HEALTH_SESSIOND_TYPE_ROTATION:
74 return "Session daemon rotation manager";
75 case HEALTH_SESSIOND_TYPE_TIMER:
76 return "Session daemon timer manager";
77 case HEALTH_SESSIOND_TYPE_ACTION_EXECUTOR:
78 return "Session daemon trigger action executor";
79 case NR_HEALTH_SESSIOND_TYPES:
80 abort();
81 }
82
83 abort();
84 };
85
86 static const char *get_consumerd_thread_name(health_type_consumerd type)
87 {
88 switch (type) {
89 case HEALTH_CONSUMERD_TYPE_CHANNEL:
90 return "Consumer daemon channel";
91 case HEALTH_CONSUMERD_TYPE_METADATA:
92 return "Consumer daemon metadata";
93 case HEALTH_CONSUMERD_TYPE_DATA:
94 return "Consumer daemon data";
95 case HEALTH_CONSUMERD_TYPE_SESSIOND:
96 return "Consumer daemon session daemon command manager";
97 case HEALTH_CONSUMERD_TYPE_METADATA_TIMER:
98 return "Consumer daemon metadata timer";
99 case NR_HEALTH_CONSUMERD_TYPES:
100 abort();
101 }
102
103 abort();
104 };
105
106 static const char *get_relayd_thread_name(health_type_relayd type)
107 {
108 switch (type) {
109 case HEALTH_RELAYD_TYPE_DISPATCHER:
110 return "Relay daemon dispatcher";
111 case HEALTH_RELAYD_TYPE_WORKER:
112 return "Relay daemon worker";
113 case HEALTH_RELAYD_TYPE_LISTENER:
114 return "Relay daemon listener";
115 case HEALTH_RELAYD_TYPE_LIVE_DISPATCHER:
116 return "Relay daemon live dispatcher";
117 case HEALTH_RELAYD_TYPE_LIVE_WORKER:
118 return "Relay daemon live worker";
119 case HEALTH_RELAYD_TYPE_LIVE_LISTENER:
120 return "Relay daemon live listener";
121 case NR_HEALTH_RELAYD_TYPES:
122 abort();
123 }
124
125 abort();
126 }
127
128 static const char *get_thread_name(int comp, int nr)
129 {
130 switch (comp) {
131 case HEALTH_COMPONENT_SESSIOND:
132 return get_sessiond_thread_name((health_type_sessiond) nr);
133 case HEALTH_COMPONENT_CONSUMERD:
134 return get_consumerd_thread_name((health_type_consumerd) nr);
135 case HEALTH_COMPONENT_RELAYD:
136 return get_relayd_thread_name((health_type_relayd) nr);
137 case NR_HEALTH_COMPONENT:
138 abort();
139 }
140
141 abort();
142 }
143
144 /*
145 * Set health socket path.
146 *
147 * Returns 0 on success or a negative errno.
148 */
149 static int set_health_socket_path(struct lttng_health *lh, int tracing_group)
150 {
151 uid_t uid;
152 const char *home;
153 int ret;
154 /* Global and home format strings */
155 const char *global_str, *home_str;
156
157 switch (lh->component) {
158 case HEALTH_COMPONENT_SESSIOND:
159 global_str = DEFAULT_GLOBAL_HEALTH_UNIX_SOCK;
160 home_str = DEFAULT_HOME_HEALTH_UNIX_SOCK;
161 break;
162 case HEALTH_COMPONENT_CONSUMERD:
163 switch (lh->consumerd_type) {
164 case LTTNG_HEALTH_CONSUMERD_UST_32:
165 global_str = DEFAULT_GLOBAL_USTCONSUMER32_HEALTH_UNIX_SOCK;
166 home_str = DEFAULT_HOME_USTCONSUMER32_HEALTH_UNIX_SOCK;
167 break;
168 case LTTNG_HEALTH_CONSUMERD_UST_64:
169 global_str = DEFAULT_GLOBAL_USTCONSUMER64_HEALTH_UNIX_SOCK;
170 home_str = DEFAULT_HOME_USTCONSUMER64_HEALTH_UNIX_SOCK;
171 break;
172 case LTTNG_HEALTH_CONSUMERD_KERNEL:
173 global_str = DEFAULT_GLOBAL_KCONSUMER_HEALTH_UNIX_SOCK;
174 home_str = DEFAULT_HOME_KCONSUMER_HEALTH_UNIX_SOCK;
175 break;
176 default:
177 return -EINVAL;
178 }
179 break;
180 case HEALTH_COMPONENT_RELAYD:
181 if (lh->health_sock_path[0] == '\0') {
182 return -EINVAL;
183 } else {
184 return 0;
185 }
186 break; /* Unreached */
187 default:
188 return -EINVAL;
189 }
190
191 uid = getuid();
192
193 if (uid == 0 || tracing_group) {
194 ret = lttng_strncpy(lh->health_sock_path, global_str, sizeof(lh->health_sock_path));
195 return ret == 0 ? 0 : -EINVAL;
196 }
197
198 /*
199 * With GNU C < 2.1, snprintf returns -1 if the target buffer
200 * is too small; With GNU C >= 2.1, snprintf returns the
201 * required size (excluding closing null).
202 */
203 home = utils_get_home_dir();
204 if (home == NULL) {
205 /* Fallback in /tmp */
206 home = "/tmp";
207 }
208
209 DIAGNOSTIC_PUSH
210 DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL
211 ret = snprintf(lh->health_sock_path, sizeof(lh->health_sock_path), home_str, home);
212 DIAGNOSTIC_POP
213 if ((ret < 0) || (ret >= sizeof(lh->health_sock_path))) {
214 return -ENOMEM;
215 }
216
217 return 0;
218 }
219
220 static struct lttng_health *lttng_health_create(enum health_component hc, unsigned int nr_threads)
221 {
222 struct lttng_health *lh;
223 int i;
224
225 lh = zmalloc<lttng_health>(sizeof(*lh) + sizeof(lh->thread[0]) * nr_threads);
226 if (!lh) {
227 return NULL;
228 }
229
230 lh->component = hc;
231 lh->state = UINT64_MAX; /* All bits in error initially */
232 lh->nr_threads = nr_threads;
233 for (i = 0; i < nr_threads; i++) {
234 lh->thread[i].p = lh;
235 }
236 return lh;
237 }
238
239 struct lttng_health *lttng_health_create_sessiond(void)
240 {
241 struct lttng_health *lh;
242
243 lh = lttng_health_create(HEALTH_COMPONENT_SESSIOND, NR_HEALTH_SESSIOND_TYPES);
244 if (!lh) {
245 return NULL;
246 }
247 return lh;
248 }
249
250 struct lttng_health *lttng_health_create_consumerd(enum lttng_health_consumerd consumerd)
251 {
252 struct lttng_health *lh;
253
254 lh = lttng_health_create(HEALTH_COMPONENT_CONSUMERD, NR_HEALTH_CONSUMERD_TYPES);
255 if (!lh) {
256 return NULL;
257 }
258 lh->consumerd_type = consumerd;
259 return lh;
260 }
261
262 struct lttng_health *lttng_health_create_relayd(const char *path)
263 {
264 int ret;
265 struct lttng_health *lh = NULL;
266
267 if (!path) {
268 goto error;
269 }
270
271 lh = lttng_health_create(HEALTH_COMPONENT_RELAYD, NR_HEALTH_RELAYD_TYPES);
272 if (!lh) {
273 goto error;
274 }
275
276 ret = lttng_strncpy(lh->health_sock_path, path, sizeof(lh->health_sock_path));
277 if (ret) {
278 goto error;
279 }
280
281 return lh;
282
283 error:
284 free(lh);
285 return NULL;
286 }
287
288 void lttng_health_destroy(struct lttng_health *lh)
289 {
290 free(lh);
291 }
292
293 int lttng_health_query(struct lttng_health *health)
294 {
295 int sock, ret, i, tracing_group;
296 struct health_comm_msg msg;
297 struct health_comm_reply reply;
298
299 if (!health) {
300 return -EINVAL;
301 }
302
303 tracing_group = lttng_check_tracing_group();
304 retry:
305 ret = set_health_socket_path(health, tracing_group);
306 if (ret) {
307 goto error;
308 }
309 /* Connect to component */
310 sock = lttcomm_connect_unix_sock(health->health_sock_path);
311 if (sock < 0) {
312 if (tracing_group) {
313 /* For tracing group, fallback to per-user */
314 tracing_group = 0;
315 goto retry;
316 }
317 ret = -1;
318 goto error;
319 }
320
321 memset(&msg, 0, sizeof(msg));
322 msg.cmd = HEALTH_CMD_CHECK;
323
324 ret = lttcomm_send_unix_sock(sock, (void *) &msg, sizeof(msg));
325 if (ret < 0) {
326 ret = -1;
327 goto close_error;
328 }
329
330 ret = lttcomm_recv_unix_sock(sock, (void *) &reply, sizeof(reply));
331 if (ret < 0) {
332 ret = -1;
333 goto close_error;
334 }
335
336 health->state = reply.ret_code;
337 for (i = 0; i < health->nr_threads; i++) {
338 if (health->state & (1ULL << i)) {
339 health->thread[i].state = -1;
340 } else {
341 health->thread[i].state = 0;
342 }
343 }
344
345 close_error:
346 {
347 int closeret;
348
349 closeret = close(sock);
350 LTTNG_ASSERT(!closeret);
351 }
352
353 error:
354 if (ret >= 0)
355 ret = 0;
356 return ret;
357 }
358
359 int lttng_health_state(const struct lttng_health *health)
360 {
361 if (!health) {
362 return -EINVAL;
363 }
364
365 if (health->state == 0) {
366 return 0;
367 } else {
368 return -1;
369 }
370 }
371
372 int lttng_health_get_nr_threads(const struct lttng_health *health)
373 {
374 if (!health) {
375 return -EINVAL;
376 }
377 return health->nr_threads;
378 }
379
380 const struct lttng_health_thread *lttng_health_get_thread(const struct lttng_health *health,
381 unsigned int nth_thread)
382 {
383 if (!health || nth_thread >= health->nr_threads) {
384 return NULL;
385 }
386 return &health->thread[nth_thread];
387 }
388
389 int lttng_health_thread_state(const struct lttng_health_thread *thread)
390 {
391 if (!thread) {
392 return -EINVAL;
393 }
394 return thread->state;
395 }
396
397 const char *lttng_health_thread_name(const struct lttng_health_thread *thread)
398 {
399 unsigned int nr;
400
401 if (!thread) {
402 return NULL;
403 }
404 nr = thread - &thread->p->thread[0];
405 return get_thread_name(thread->p->component, nr);
406 }
This page took 0.037617 seconds and 5 git commands to generate.