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