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