Health check: implement health check query in sessiond and consumerd
[lttng-tools.git] / src / lib / lttng-ctl / lttng-ctl-health.c
CommitLineData
6c71277b
MD
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 * This library is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License, version 2.1 only,
11 * as published by the Free Software Foundation.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this library; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#include <unistd.h>
24#include <sys/types.h>
25#include <stdint.h>
26#include <limits.h>
27#include <errno.h>
28#include <lttng/health-internal.h>
29
30#include <bin/lttng-sessiond/health-sessiond.h>
31#include <bin/lttng-consumerd/health-consumerd.h>
32#include <bin/lttng-relayd/health-relayd.h>
33#include <common/defaults.h>
34#include <common/utils.h>
35
36#include "lttng-ctl-helper.h"
37
38enum health_component {
39 HEALTH_COMPONENT_SESSIOND,
40 HEALTH_COMPONENT_CONSUMERD,
41 HEALTH_COMPONENT_RELAYD,
42
43 NR_HEALTH_COMPONENT,
44};
45
46struct lttng_health_thread {
47 struct lttng_health *p;
48 int state;
49};
50
51struct lttng_health {
52 enum health_component component;
53 uint64_t state;
54 unsigned int nr_threads;
55 char health_sock_path[PATH_MAX];
56 /* For consumer health only */
57 enum lttng_health_consumerd consumerd_type;
58 struct lttng_health_thread thread[];
59};
60
61static
62const char *sessiond_thread_name[NR_HEALTH_SESSIOND_TYPES] = {
63 [ HEALTH_SESSIOND_TYPE_CMD ] = "Session daemon command",
64 [ HEALTH_SESSIOND_TYPE_APP_MANAGE ] = "Session daemon application manager",
65 [ HEALTH_SESSIOND_TYPE_APP_REG ] = "Session daemon application registration",
66 [ HEALTH_SESSIOND_TYPE_KERNEL ] = "Session daemon kernel",
67 [ HEALTH_SESSIOND_TYPE_CONSUMER ] = "Session daemon consumer manager",
68 [ HEALTH_SESSIOND_TYPE_HT_CLEANUP ] = "Session daemon hash table cleanup",
69 [ HEALTH_SESSIOND_TYPE_APP_MANAGE_NOTIFY ] = "Session daemon application notification manager",
70 [ HEALTH_SESSIOND_TYPE_APP_REG_DISPATCH ] = "Session daemon application registration dispatcher",
71};
72
73static
74const char *consumerd_thread_name[NR_HEALTH_CONSUMERD_TYPES] = {
75 [ HEALTH_CONSUMERD_TYPE_CHANNEL ] = "Consumer daemon channel",
76 [ HEALTH_CONSUMERD_TYPE_METADATA ] = "Consumer daemon metadata",
77 [ HEALTH_CONSUMERD_TYPE_DATA ] = "Consumer daemon data",
78 [ HEALTH_CONSUMERD_TYPE_SESSIOND ] = "Consumer daemon session daemon command manager",
79 [ HEALTH_CONSUMERD_TYPE_METADATA_TIMER ] = "Consumer daemon metadata timer",
80};
81
82static
83const char *relayd_thread_name[NR_HEALTH_RELAYD_TYPES] = {
84 [ HEALTH_RELAYD_TYPE_DISPATCHER ] = "Relay daemon dispatcher",
85 [ HEALTH_RELAYD_TYPE_WORKER ] = "Relay daemon worker",
86 [ HEALTH_RELAYD_TYPE_LISTENER ] = "Relay daemon listener",
87};
88
89static
90const char **thread_name[NR_HEALTH_COMPONENT] = {
91 [ HEALTH_COMPONENT_SESSIOND ] = sessiond_thread_name,
92 [ HEALTH_COMPONENT_CONSUMERD] = consumerd_thread_name,
93 [ HEALTH_COMPONENT_RELAYD ] = relayd_thread_name,
94};
95
96/*
97 * Set health socket path.
98 *
99 * Returns 0 on success or -ENOMEM.
100 */
101static
102int set_health_socket_path(struct lttng_health *lh,
103 int tracing_group)
104{
105 uid_t uid;
106 const char *home;
107 int ret;
108 /* Global and home format strings */
109 const char *global_str, *home_str;
110
111 switch (lh->component) {
112 case HEALTH_COMPONENT_SESSIOND:
113 global_str = DEFAULT_GLOBAL_HEALTH_UNIX_SOCK;
114 home_str = DEFAULT_HOME_HEALTH_UNIX_SOCK;
115 break;
116 case HEALTH_COMPONENT_CONSUMERD:
117 switch (lh->consumerd_type) {
118 case LTTNG_HEALTH_CONSUMERD_UST_32:
119 global_str = DEFAULT_GLOBAL_USTCONSUMER32_HEALTH_UNIX_SOCK;
120 home_str = DEFAULT_HOME_USTCONSUMER32_HEALTH_UNIX_SOCK;
121 break;
122 case LTTNG_HEALTH_CONSUMERD_UST_64:
123 global_str = DEFAULT_GLOBAL_USTCONSUMER64_HEALTH_UNIX_SOCK;
124 home_str = DEFAULT_HOME_USTCONSUMER64_HEALTH_UNIX_SOCK;
125 break;
126 case LTTNG_HEALTH_CONSUMERD_KERNEL:
127 global_str = DEFAULT_GLOBAL_KCONSUMER_HEALTH_UNIX_SOCK;
128 home_str = DEFAULT_HOME_KCONSUMER_HEALTH_UNIX_SOCK;
129 break;
130 default:
131 return -EINVAL;
132 }
133 break;
134 case HEALTH_COMPONENT_RELAYD:
135 if (lh->health_sock_path[0] == '\0') {
136 return -EINVAL;
137 } else {
138 return 0;
139 }
140 break; /* Unreached */
141 default:
142 return -EINVAL;
143 }
144
145 uid = getuid();
146
147 if (uid == 0 || tracing_group) {
148 lttng_ctl_copy_string(lh->health_sock_path,
149 global_str,
150 sizeof(lh->health_sock_path));
151 return 0;
152 }
153
154 /*
155 * With GNU C < 2.1, snprintf returns -1 if the target buffer
156 * is too small; With GNU C >= 2.1, snprintf returns the
157 * required size (excluding closing null).
158 */
159 home = utils_get_home_dir();
160 if (home == NULL) {
161 /* Fallback in /tmp */
162 home = "/tmp";
163 }
164
165 ret = snprintf(lh->health_sock_path, sizeof(lh->health_sock_path),
166 home_str, home);
167 if ((ret < 0) || (ret >= sizeof(lh->health_sock_path))) {
168 return -ENOMEM;
169 }
170
171 return 0;
172}
173
174static
175struct lttng_health *lttng_health_create(enum health_component hc,
176 unsigned int nr_threads)
177{
178 struct lttng_health *lh;
179 int i;
180
181 lh = zmalloc(sizeof(*lh) + sizeof(lh->thread[0]) * nr_threads);
182 if (!lh) {
183 return NULL;
184 }
185
186 lh->component = hc;
187 lh->state = UINT64_MAX; /* All bits in error initially */
188 lh->nr_threads = nr_threads;
189 for (i = 0; i < nr_threads; i++) {
190 lh->thread[i].p = lh;
191 }
192 return lh;
193}
194
195struct lttng_health *lttng_health_create_sessiond(void)
196{
197 struct lttng_health *lh;
198
199 lh = lttng_health_create(HEALTH_COMPONENT_SESSIOND,
200 NR_HEALTH_SESSIOND_TYPES);
201 if (!lh) {
202 return NULL;
203 }
204 return lh;
205}
206
207struct lttng_health *
208 lttng_health_create_consumerd(enum lttng_health_consumerd consumerd)
209{
210 struct lttng_health *lh;
211
212 lh = lttng_health_create(HEALTH_COMPONENT_CONSUMERD,
213 NR_HEALTH_CONSUMERD_TYPES);
214 if (!lh) {
215 return NULL;
216 }
217 lh->consumerd_type = consumerd;
218 return lh;
219}
220
221struct lttng_health *lttng_health_create_relayd(const char *path)
222{
223 struct lttng_health *lh;
224
225 if (!path) {
226 return NULL;
227 }
228
229 lh = lttng_health_create(HEALTH_COMPONENT_RELAYD,
230 NR_HEALTH_RELAYD_TYPES);
231 if (!lh) {
232 return NULL;
233 }
234 lttng_ctl_copy_string(lh->health_sock_path, path,
235 sizeof(lh->health_sock_path));
236 return lh;
237}
238
239void lttng_health_destroy(struct lttng_health *lh)
240{
241 free(lh);
242}
243
244int lttng_health_query(struct lttng_health *health)
245{
246 int sock, ret, i, tracing_group;
247 struct health_comm_msg msg;
248 struct health_comm_reply reply;
249
250 if (!health) {
251 return -EINVAL;
252 }
253
254 tracing_group = lttng_check_tracing_group();
255retry:
256 ret = set_health_socket_path(health, tracing_group);
257 if (ret) {
258 goto error;
259 }
260 /* Connect to the sesssion daemon */
261 sock = lttcomm_connect_unix_sock(health->health_sock_path);
262 if (sock < 0) {
263 if (tracing_group) {
264 /* For tracing group, fallback to per-user */
265 tracing_group = 0;
266 goto retry;
267 }
268 ret = -1;
269 goto error;
270 }
271
272 msg.cmd = HEALTH_CMD_CHECK;
273
274 ret = lttcomm_send_unix_sock(sock, (void *)&msg, sizeof(msg));
275 if (ret < 0) {
276 ret = -1;
277 goto close_error;
278 }
279
280 ret = lttcomm_recv_unix_sock(sock, (void *)&reply, sizeof(reply));
281 if (ret < 0) {
282 ret = -1;
283 goto close_error;
284 }
285
286 health->state = reply.ret_code;
287 for (i = 0; i < health->nr_threads; i++) {
288 if (health->state & (1ULL << i)) {
289 health->thread[i].state = -1;
290 } else {
291 health->thread[i].state = 0;
292 }
293 }
294
295close_error:
296 {
297 int closeret;
298
299 closeret = close(sock);
300 assert(!closeret);
301 }
302
303error:
304 if (ret >= 0)
305 ret = 0;
306 return ret;
307}
308
309int lttng_health_state(const struct lttng_health *health)
310{
311 if (!health) {
312 return -EINVAL;
313 }
314
315 if (health->state == 0) {
316 return 0;
317 } else {
318 return -1;
319 }
320}
321
322int lttng_health_get_nr_threads(const struct lttng_health *health)
323{
324 if (!health) {
325 return -EINVAL;
326 }
327 return health->nr_threads;
328}
329
330const struct lttng_health_thread *
331 lttng_health_get_thread(const struct lttng_health *health,
332 unsigned int nth_thread)
333{
334 if (!health || nth_thread >= health->nr_threads) {
335 return NULL;
336 }
337 return &health->thread[nth_thread];
338}
339
340int lttng_health_thread_state(const struct lttng_health_thread *thread)
341{
342 if (!thread) {
343 return -EINVAL;
344 }
345 return thread->state;
346}
347
348const char *lttng_health_thread_name(const struct lttng_health_thread *thread)
349{
350 unsigned int nr;
351
352 if (!thread) {
353 return NULL;
354 }
355 nr = thread - &thread->p->thread[0];
356 return thread_name[thread->p->component][nr];
357}
This page took 0.055439 seconds and 5 git commands to generate.