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