9ae3d4174969e666f13ad56cfe8240e3a147d237
[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 -ENOMEM.
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 lttng_ctl_copy_string(lh->health_sock_path,
147 global_str,
148 sizeof(lh->health_sock_path));
149 return 0;
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 struct lttng_health *lh;
222
223 if (!path) {
224 return NULL;
225 }
226
227 lh = lttng_health_create(HEALTH_COMPONENT_RELAYD,
228 NR_HEALTH_RELAYD_TYPES);
229 if (!lh) {
230 return NULL;
231 }
232 lttng_ctl_copy_string(lh->health_sock_path, path,
233 sizeof(lh->health_sock_path));
234 return lh;
235 }
236
237 void lttng_health_destroy(struct lttng_health *lh)
238 {
239 free(lh);
240 }
241
242 int lttng_health_query(struct lttng_health *health)
243 {
244 int sock, ret, i, tracing_group;
245 struct health_comm_msg msg;
246 struct health_comm_reply reply;
247
248 if (!health) {
249 return -EINVAL;
250 }
251
252 tracing_group = lttng_check_tracing_group();
253 retry:
254 ret = set_health_socket_path(health, tracing_group);
255 if (ret) {
256 goto error;
257 }
258 /* Connect to component */
259 sock = lttcomm_connect_unix_sock(health->health_sock_path);
260 if (sock < 0) {
261 if (tracing_group) {
262 /* For tracing group, fallback to per-user */
263 tracing_group = 0;
264 goto retry;
265 }
266 ret = -1;
267 goto error;
268 }
269
270 memset(&msg, 0, sizeof(msg));
271 msg.cmd = HEALTH_CMD_CHECK;
272
273 ret = lttcomm_send_unix_sock(sock, (void *)&msg, sizeof(msg));
274 if (ret < 0) {
275 ret = -1;
276 goto close_error;
277 }
278
279 ret = lttcomm_recv_unix_sock(sock, (void *)&reply, sizeof(reply));
280 if (ret < 0) {
281 ret = -1;
282 goto close_error;
283 }
284
285 health->state = reply.ret_code;
286 for (i = 0; i < health->nr_threads; i++) {
287 if (health->state & (1ULL << i)) {
288 health->thread[i].state = -1;
289 } else {
290 health->thread[i].state = 0;
291 }
292 }
293
294 close_error:
295 {
296 int closeret;
297
298 closeret = close(sock);
299 assert(!closeret);
300 }
301
302 error:
303 if (ret >= 0)
304 ret = 0;
305 return ret;
306 }
307
308 int lttng_health_state(const struct lttng_health *health)
309 {
310 if (!health) {
311 return -EINVAL;
312 }
313
314 if (health->state == 0) {
315 return 0;
316 } else {
317 return -1;
318 }
319 }
320
321 int lttng_health_get_nr_threads(const struct lttng_health *health)
322 {
323 if (!health) {
324 return -EINVAL;
325 }
326 return health->nr_threads;
327 }
328
329 const struct lttng_health_thread *
330 lttng_health_get_thread(const struct lttng_health *health,
331 unsigned int nth_thread)
332 {
333 if (!health || nth_thread >= health->nr_threads) {
334 return NULL;
335 }
336 return &health->thread[nth_thread];
337 }
338
339 int lttng_health_thread_state(const struct lttng_health_thread *thread)
340 {
341 if (!thread) {
342 return -EINVAL;
343 }
344 return thread->state;
345 }
346
347 const char *lttng_health_thread_name(const struct lttng_health_thread *thread)
348 {
349 unsigned int nr;
350
351 if (!thread) {
352 return NULL;
353 }
354 nr = thread - &thread->p->thread[0];
355 return thread_name[thread->p->component][nr];
356 }
This page took 0.051769 seconds and 3 git commands to generate.