Build fix: missing stdio.h include in signal-helper.hpp
[lttng-tools.git] / src / bin / lttng-relayd / health-relayd.cpp
CommitLineData
65931c8b 1/*
ab5be9fa 2 * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
65931c8b 3 *
ab5be9fa 4 * SPDX-License-Identifier: GPL-2.0-only
65931c8b 5 *
65931c8b
MD
6 */
7
6c1c0768 8#define _LGPL_SOURCE
65931c8b
MD
9#include <fcntl.h>
10#include <getopt.h>
11#include <grp.h>
12#include <limits.h>
13#include <pthread.h>
14#include <signal.h>
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <sys/ipc.h>
19#include <sys/resource.h>
20#include <sys/shm.h>
21#include <sys/socket.h>
22#include <sys/stat.h>
23#include <sys/types.h>
24#include <urcu/list.h>
25#include <poll.h>
26#include <unistd.h>
27#include <sys/mman.h>
65931c8b 28#include <urcu/compiler.h>
65931c8b
MD
29#include <inttypes.h>
30
c9e313bc
SM
31#include <common/defaults.hpp>
32#include <common/common.hpp>
33#include <common/consumer/consumer.hpp>
34#include <common/consumer/consumer-timer.hpp>
35#include <common/compat/poll.hpp>
36#include <common/sessiond-comm/sessiond-comm.hpp>
37#include <common/utils.hpp>
38#include <common/compat/getenv.hpp>
39#include <common/fd-tracker/utils.hpp>
65931c8b 40
c9e313bc
SM
41#include "lttng-relayd.hpp"
42#include "health-relayd.hpp"
65931c8b
MD
43
44/* Global health check unix path */
094fe907
MD
45static
46char health_unix_sock_path[PATH_MAX];
65931c8b 47
794e2e5f 48int health_quit_pipe[2] = { -1, -1 };
65931c8b 49
65931c8b
MD
50/*
51 * Send data on a unix socket using the liblttsessiondcomm API.
52 *
53 * Return lttcomm error code.
54 */
55static int send_unix_sock(int sock, void *buf, size_t len)
56{
57 /* Check valid length */
58 if (len == 0) {
59 return -1;
60 }
61
62 return lttcomm_send_unix_sock(sock, buf, len);
63}
64
65static int create_lttng_rundir_with_perm(const char *rundir)
66{
67 int ret;
68
69 DBG3("Creating LTTng run directory: %s", rundir);
70
71 ret = mkdir(rundir, S_IRWXU);
72 if (ret < 0) {
73 if (errno != EEXIST) {
74 ERR("Unable to create %s", rundir);
75 goto error;
76 } else {
77 ret = 0;
78 }
79 } else if (ret == 0) {
80 int is_root = !getuid();
81
82 if (is_root) {
28ab59d0
JR
83 gid_t gid;
84
85 ret = utils_get_group_id(tracing_group_name, true, &gid);
86 if (ret) {
87 /* Default to root group. */
88 gid = 0;
89 }
90
91 ret = chown(rundir, 0, gid);
65931c8b
MD
92 if (ret < 0) {
93 ERR("Unable to set group on %s", rundir);
94 PERROR("chown");
95 ret = -1;
96 goto error;
97 }
98
99 ret = chmod(rundir,
100 S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
101 if (ret < 0) {
f7b09ec2 102 ERR("Unable to set permissions on %s", rundir);
65931c8b
MD
103 PERROR("chmod");
104 ret = -1;
105 goto error;
106 }
107 }
108 }
109
110error:
111 return ret;
112}
113
094fe907
MD
114static
115int parse_health_env(void)
116{
117 const char *health_path;
118
e8fa9fb0 119 health_path = lttng_secure_getenv(LTTNG_RELAYD_HEALTH_ENV);
094fe907
MD
120 if (health_path) {
121 strncpy(health_unix_sock_path, health_path,
122 PATH_MAX);
123 health_unix_sock_path[PATH_MAX - 1] = '\0';
124 }
125
126 return 0;
127}
128
65931c8b
MD
129static
130int setup_health_path(void)
131{
132 int is_root, ret = 0;
4f00620d
JG
133 const char *home_path = NULL;
134 char *rundir = NULL, *relayd_path = NULL;
65931c8b 135
094fe907
MD
136 ret = parse_health_env();
137 if (ret) {
138 return ret;
139 }
140
65931c8b
MD
141 is_root = !getuid();
142
143 if (is_root) {
c3844e39 144 rundir = strdup(DEFAULT_LTTNG_RUNDIR);
b6ab01aa
MD
145 if (!rundir) {
146 ret = -ENOMEM;
147 goto end;
148 }
65931c8b
MD
149 } else {
150 /*
151 * Create rundir from home path. This will create something like
152 * $HOME/.lttng
153 */
154 home_path = utils_get_home_dir();
155
156 if (home_path == NULL) {
157 /* TODO: Add --socket PATH option */
158 ERR("Can't get HOME directory for sockets creation.");
159 ret = -EPERM;
160 goto end;
161 }
162
c3844e39 163 ret = asprintf(&rundir, DEFAULT_LTTNG_HOME_RUNDIR, home_path);
65931c8b
MD
164 if (ret < 0) {
165 ret = -ENOMEM;
166 goto end;
167 }
168 }
169
c3844e39 170 ret = asprintf(&relayd_path, DEFAULT_RELAYD_PATH, rundir);
65931c8b
MD
171 if (ret < 0) {
172 ret = -ENOMEM;
173 goto end;
174 }
175
c3844e39 176 ret = create_lttng_rundir_with_perm(rundir);
65931c8b
MD
177 if (ret < 0) {
178 goto end;
179 }
180
181 ret = create_lttng_rundir_with_perm(relayd_path);
182 if (ret < 0) {
183 goto end;
184 }
185
186 if (is_root) {
187 if (strlen(health_unix_sock_path) != 0) {
188 goto end;
189 }
190 snprintf(health_unix_sock_path, sizeof(health_unix_sock_path),
191 DEFAULT_GLOBAL_RELAY_HEALTH_UNIX_SOCK,
d1f721c5 192 (int) getpid());
65931c8b
MD
193 } else {
194 /* Set health check Unix path */
195 if (strlen(health_unix_sock_path) != 0) {
196 goto end;
197 }
198
199 snprintf(health_unix_sock_path, sizeof(health_unix_sock_path),
200 DEFAULT_HOME_RELAY_HEALTH_UNIX_SOCK,
d1f721c5 201 home_path, (int) getpid());
65931c8b
MD
202 }
203
204end:
c3844e39 205 free(rundir);
edd94901 206 free(relayd_path);
65931c8b
MD
207 return ret;
208}
209
1c9bd75b
JG
210static
211int accept_unix_socket(void *data, int *out_fd)
212{
213 int ret;
214 int accepting_sock = *((int *) data);
215
216 ret = lttcomm_accept_unix_sock(accepting_sock);
217 if (ret < 0) {
218 goto end;
219 }
220
221 *out_fd = ret;
222 ret = 0;
223end:
224 return ret;
225}
226
d7eddab9
JG
227static
228int open_unix_socket(void *data, int *out_fd)
229{
230 int ret;
ac497a37 231 const char *path = (const char *) data;
d7eddab9
JG
232
233 ret = lttcomm_create_unix_sock(path);
234 if (ret < 0) {
235 goto end;
236 }
237
238 *out_fd = ret;
239 ret = 0;
240end:
241 return ret;
242}
243
65931c8b
MD
244/*
245 * Thread managing health check socket.
246 */
f46376a1 247void *thread_manage_health_relayd(void *data __attribute__((unused)))
65931c8b 248{
8a00688e
MJ
249 int sock = -1, new_sock = -1, ret, i, err = -1;
250 uint32_t nb_fd;
65931c8b
MD
251 struct lttng_poll_event events;
252 struct health_comm_msg msg;
253 struct health_comm_reply reply;
254 int is_root;
d7eddab9 255 char *sock_name;
65931c8b
MD
256
257 DBG("[thread] Manage health check started");
258
259 setup_health_path();
260
261 rcu_register_thread();
262
263 /* We might hit an error path before this is created. */
264 lttng_poll_init(&events);
265
266 /* Create unix socket */
d7eddab9
JG
267 ret = asprintf(&sock_name, "Unix socket @ %s", health_unix_sock_path);
268 if (ret == -1) {
269 PERROR("Failed to allocate unix socket name");
270 err = -1;
271 goto error;
272 }
273 ret = fd_tracker_open_unsuspendable_fd(the_fd_tracker, &sock,
274 (const char **) &sock_name, 1, open_unix_socket,
275 health_unix_sock_path);
276 free(sock_name);
277 if (ret < 0) {
65931c8b 278 ERR("Unable to create health check Unix socket");
7568ddbf 279 err = -1;
65931c8b
MD
280 goto error;
281 }
282
283 is_root = !getuid();
284 if (is_root) {
285 /* lttng health client socket path permissions */
28ab59d0
JR
286 gid_t gid;
287
288 ret = utils_get_group_id(tracing_group_name, true, &gid);
289 if (ret) {
290 /* Default to root group. */
291 gid = 0;
292 }
293
294 ret = chown(health_unix_sock_path, 0, gid);
65931c8b
MD
295 if (ret < 0) {
296 ERR("Unable to set group on %s", health_unix_sock_path);
297 PERROR("chown");
7568ddbf 298 err = -1;
65931c8b
MD
299 goto error;
300 }
301
302 ret = chmod(health_unix_sock_path,
303 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
304 if (ret < 0) {
305 ERR("Unable to set permissions on %s", health_unix_sock_path);
306 PERROR("chmod");
7568ddbf 307 err = -1;
65931c8b
MD
308 goto error;
309 }
310 }
311
312 /*
313 * Set the CLOEXEC flag. Return code is useless because either way, the
314 * show must go on.
315 */
316 (void) utils_set_fd_cloexec(sock);
317
318 ret = lttcomm_listen_unix_sock(sock);
319 if (ret < 0) {
320 goto error;
321 }
322
aa91fbc5
JG
323 /* Size is set to 2 for the unix socket and quit pipe. */
324 ret = fd_tracker_util_poll_create(the_fd_tracker,
325 "Health management thread epoll", &events, 2,
326 LTTNG_CLOEXEC);
65931c8b
MD
327 if (ret < 0) {
328 ERR("Poll set creation failed");
329 goto error;
330 }
331
332 ret = lttng_poll_add(&events, health_quit_pipe[0], LPOLLIN);
333 if (ret < 0) {
334 goto error;
335 }
336
337 /* Add the application registration socket */
338 ret = lttng_poll_add(&events, sock, LPOLLIN | LPOLLPRI);
339 if (ret < 0) {
340 goto error;
341 }
342
3fd27398
MD
343 lttng_relay_notify_ready();
344
65931c8b 345 while (1) {
1c9bd75b
JG
346 char *accepted_socket_name;
347
65931c8b
MD
348 DBG("Health check ready");
349
350 /* Inifinite blocking call, waiting for transmission */
351restart:
352 ret = lttng_poll_wait(&events, -1);
353 if (ret < 0) {
354 /*
355 * Restart interrupted system call.
356 */
357 if (errno == EINTR) {
358 goto restart;
359 }
360 goto error;
361 }
362
363 nb_fd = ret;
364
365 for (i = 0; i < nb_fd; i++) {
366 /* Fetch once the poll data */
8a00688e
MJ
367 const auto revents = LTTNG_POLL_GETEV(&events, i);
368 const auto pollfd = LTTNG_POLL_GETFD(&events, i);
65931c8b 369
8a00688e
MJ
370 /* Activity on thread quit pipe, exiting. */
371 if (pollfd == health_quit_pipe[0]) {
372 DBG("Activity on thread quit pipe");
65931c8b
MD
373 err = 0;
374 goto exit;
375 }
376
377 /* Event on the registration socket */
378 if (pollfd == sock) {
03e43155
MD
379 if (revents & LPOLLIN) {
380 continue;
381 } else if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) {
65931c8b
MD
382 ERR("Health socket poll error");
383 goto error;
03e43155
MD
384 } else {
385 ERR("Unexpected poll events %u for sock %d", revents, pollfd);
386 goto error;
65931c8b
MD
387 }
388 }
389 }
390
1c9bd75b
JG
391 ret = asprintf(&accepted_socket_name, "Socket accepted from unix socket @ %s",
392 health_unix_sock_path);
393 if (ret == -1) {
394 PERROR("Failed to allocate name of accepted socket from unix socket @ %s",
395 health_unix_sock_path);
396 goto error;
397 }
398 ret = fd_tracker_open_unsuspendable_fd(the_fd_tracker, &new_sock,
399 (const char **) &accepted_socket_name, 1,
400 accept_unix_socket, &sock);
401 free(accepted_socket_name);
402 if (ret < 0) {
65931c8b
MD
403 goto error;
404 }
405
406 /*
407 * Set the CLOEXEC flag. Return code is useless because either way, the
408 * show must go on.
409 */
410 (void) utils_set_fd_cloexec(new_sock);
411
412 DBG("Receiving data from client for health...");
413 ret = lttcomm_recv_unix_sock(new_sock, (void *)&msg, sizeof(msg));
414 if (ret <= 0) {
415 DBG("Nothing recv() from client... continuing");
1c9bd75b
JG
416 ret = fd_tracker_close_unsuspendable_fd(the_fd_tracker,
417 &new_sock, 1, fd_tracker_util_close_fd,
418 NULL);
65931c8b
MD
419 if (ret) {
420 PERROR("close");
421 }
422 new_sock = -1;
423 continue;
424 }
425
426 rcu_thread_online();
427
a0377dfe 428 LTTNG_ASSERT(msg.cmd == HEALTH_CMD_CHECK);
65931c8b 429
53efb85a 430 memset(&reply, 0, sizeof(reply));
65931c8b
MD
431 for (i = 0; i < NR_HEALTH_RELAYD_TYPES; i++) {
432 /*
433 * health_check_state return 0 if thread is in
434 * error.
435 */
436 if (!health_check_state(health_relayd, i)) {
437 reply.ret_code |= 1ULL << i;
438 }
439 }
440
441 DBG2("Health check return value %" PRIx64, reply.ret_code);
442
443 ret = send_unix_sock(new_sock, (void *) &reply, sizeof(reply));
444 if (ret < 0) {
445 ERR("Failed to send health data back to client");
446 }
447
448 /* End of transmission */
1c9bd75b
JG
449 ret = fd_tracker_close_unsuspendable_fd(the_fd_tracker,
450 &new_sock, 1, fd_tracker_util_close_fd,
451 NULL);
65931c8b
MD
452 if (ret) {
453 PERROR("close");
454 }
455 new_sock = -1;
456 }
457
65931c8b 458error:
81714439
JG
459 lttng_relay_stop_threads();
460exit:
65931c8b
MD
461 if (err) {
462 ERR("Health error occurred in %s", __func__);
463 }
464 DBG("Health check thread dying");
465 unlink(health_unix_sock_path);
466 if (sock >= 0) {
d7eddab9
JG
467 ret = fd_tracker_close_unsuspendable_fd(the_fd_tracker, &sock,
468 1, fd_tracker_util_close_fd, NULL);
65931c8b
MD
469 if (ret) {
470 PERROR("close");
471 }
472 }
473
dcbcae3e
MD
474 /*
475 * We do NOT rmdir rundir nor the relayd path because there are
476 * other processes using them.
477 */
478
aa91fbc5 479 (void) fd_tracker_util_poll_clean(the_fd_tracker, &events);
65931c8b
MD
480
481 rcu_unregister_thread();
482 return NULL;
483}
This page took 0.079589 seconds and 4 git commands to generate.