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