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