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