Unlink rundir files individually
[lttng-tools.git] / src / bin / lttng-consumerd / health-consumerd.c
CommitLineData
5c635c72
MD
1/*
2 * Copyright (C) 2013 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2 only,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18#define _GNU_SOURCE
19#include <fcntl.h>
20#include <getopt.h>
21#include <grp.h>
22#include <limits.h>
23#include <pthread.h>
24#include <signal.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <sys/ipc.h>
29#include <sys/resource.h>
30#include <sys/shm.h>
31#include <sys/socket.h>
32#include <sys/stat.h>
33#include <sys/types.h>
34#include <urcu/list.h>
35#include <poll.h>
36#include <unistd.h>
37#include <sys/mman.h>
38#include <assert.h>
39#include <config.h>
40#include <urcu/compiler.h>
41#include <ulimit.h>
6c71277b 42#include <inttypes.h>
5c635c72
MD
43
44#include <common/defaults.h>
45#include <common/common.h>
46#include <common/consumer.h>
47#include <common/consumer-timer.h>
48#include <common/compat/poll.h>
49#include <common/sessiond-comm/sessiond-comm.h>
50#include <common/utils.h>
51
52#include "lttng-consumerd.h"
53#include "health-consumerd.h"
54
55/* Global health check unix path */
56static char health_unix_sock_path[PATH_MAX];
57
58int health_quit_pipe[2];
59
60/*
61 * Check if the thread quit pipe was triggered.
62 *
63 * Return 1 if it was triggered else 0;
64 */
65static
66int check_health_quit_pipe(int fd, uint32_t events)
67{
68 if (fd == health_quit_pipe[0] && (events & LPOLLIN)) {
69 return 1;
70 }
71
72 return 0;
73}
74
75/*
76 * Send data on a unix socket using the liblttsessiondcomm API.
77 *
78 * Return lttcomm error code.
79 */
80static int send_unix_sock(int sock, void *buf, size_t len)
81{
82 /* Check valid length */
83 if (len == 0) {
84 return -1;
85 }
86
87 return lttcomm_send_unix_sock(sock, buf, len);
88}
89
90static
91int setup_health_path(void)
92{
93 int is_root, ret = 0;
94 enum lttng_consumer_type type;
95 const char *home_path;
96
97 type = lttng_consumer_get_type();
98 is_root = !getuid();
99
100 if (is_root) {
101 if (strlen(health_unix_sock_path) != 0) {
102 goto end;
103 }
104 switch (type) {
105 case LTTNG_CONSUMER_KERNEL:
106 snprintf(health_unix_sock_path, sizeof(health_unix_sock_path),
107 DEFAULT_GLOBAL_KCONSUMER_HEALTH_UNIX_SOCK);
108 break;
109 case LTTNG_CONSUMER64_UST:
110 snprintf(health_unix_sock_path, sizeof(health_unix_sock_path),
111 DEFAULT_GLOBAL_USTCONSUMER64_HEALTH_UNIX_SOCK);
112 break;
113 case LTTNG_CONSUMER32_UST:
114 snprintf(health_unix_sock_path, sizeof(health_unix_sock_path),
115 DEFAULT_GLOBAL_USTCONSUMER32_HEALTH_UNIX_SOCK);
116 break;
117 default:
118 ret = -EINVAL;
119 goto end;
120 }
121 } else {
122 static char *rundir;
123
124 home_path = utils_get_home_dir();
125 if (home_path == NULL) {
126 /* TODO: Add --socket PATH option */
127 ERR("Can't get HOME directory for sockets creation.");
128 ret = -EPERM;
129 goto end;
130 }
131
132 /*
133 * Create rundir from home path. This will create something like
134 * $HOME/.lttng
135 */
136 ret = asprintf(&rundir, DEFAULT_LTTNG_HOME_RUNDIR, home_path);
137 if (ret < 0) {
138 ret = -ENOMEM;
139 goto end;
140 }
141
142 /* Set health check Unix path */
143 if (strlen(health_unix_sock_path) != 0) {
144 goto end;
145 }
146 switch (type) {
147 case LTTNG_CONSUMER_KERNEL:
148 snprintf(health_unix_sock_path, sizeof(health_unix_sock_path),
149 DEFAULT_HOME_KCONSUMER_HEALTH_UNIX_SOCK, rundir);
150 break;
151 case LTTNG_CONSUMER64_UST:
152 snprintf(health_unix_sock_path, sizeof(health_unix_sock_path),
153 DEFAULT_HOME_USTCONSUMER64_HEALTH_UNIX_SOCK, rundir);
154 break;
155 case LTTNG_CONSUMER32_UST:
156 snprintf(health_unix_sock_path, sizeof(health_unix_sock_path),
157 DEFAULT_HOME_USTCONSUMER32_HEALTH_UNIX_SOCK, rundir);
158 break;
159 default:
160 ret = -EINVAL;
161 goto end;
162 }
163 }
164
165end:
166 return ret;
167}
168
169/*
170 * Thread managing health check socket.
171 */
172void *thread_manage_health(void *data)
173{
174 int sock = -1, new_sock = -1, ret, i, pollfd, err = -1;
175 uint32_t revents, nb_fd;
176 struct lttng_poll_event events;
177 struct health_comm_msg msg;
178 struct health_comm_reply reply;
6c71277b 179 int is_root;
5c635c72
MD
180
181 DBG("[thread] Manage health check started");
182
183 setup_health_path();
184
185 rcu_register_thread();
186
187 /* We might hit an error path before this is created. */
188 lttng_poll_init(&events);
189
190 /* Create unix socket */
191 sock = lttcomm_create_unix_sock(health_unix_sock_path);
192 if (sock < 0) {
193 ERR("Unable to create health check Unix socket");
194 ret = -1;
195 goto error;
196 }
197
6c71277b
MD
198 is_root = !getuid();
199 if (is_root) {
200 /* lttng health client socket path permissions */
201 ret = chown(health_unix_sock_path, 0,
202 utils_get_group_id(tracing_group_name));
203 if (ret < 0) {
204 ERR("Unable to set group on %s", health_unix_sock_path);
205 PERROR("chown");
206 ret = -1;
207 goto error;
208 }
209
210 ret = chmod(health_unix_sock_path,
211 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
212 if (ret < 0) {
213 ERR("Unable to set permissions on %s", health_unix_sock_path);
214 PERROR("chmod");
215 ret = -1;
216 goto error;
217 }
218 }
219
5c635c72
MD
220 /*
221 * Set the CLOEXEC flag. Return code is useless because either way, the
222 * show must go on.
223 */
224 (void) utils_set_fd_cloexec(sock);
225
226 ret = lttcomm_listen_unix_sock(sock);
227 if (ret < 0) {
228 goto error;
229 }
230
231 /* Size is set to 1 for the consumer_channel pipe */
232 ret = lttng_poll_create(&events, 2, LTTNG_CLOEXEC);
233 if (ret < 0) {
234 ERR("Poll set creation failed");
235 goto error;
236 }
237
238 ret = lttng_poll_add(&events, health_quit_pipe[0], LPOLLIN);
239 if (ret < 0) {
240 goto error;
241 }
242
243 /* Add the application registration socket */
244 ret = lttng_poll_add(&events, sock, LPOLLIN | LPOLLPRI);
245 if (ret < 0) {
246 goto error;
247 }
248
249 while (1) {
250 DBG("Health check ready");
251
252 /* Inifinite blocking call, waiting for transmission */
253restart:
254 ret = lttng_poll_wait(&events, -1);
255 if (ret < 0) {
256 /*
257 * Restart interrupted system call.
258 */
259 if (errno == EINTR) {
260 goto restart;
261 }
262 goto error;
263 }
264
265 nb_fd = ret;
266
267 for (i = 0; i < nb_fd; i++) {
268 /* Fetch once the poll data */
269 revents = LTTNG_POLL_GETEV(&events, i);
270 pollfd = LTTNG_POLL_GETFD(&events, i);
271
272 /* Thread quit pipe has been closed. Killing thread. */
273 ret = check_health_quit_pipe(pollfd, revents);
274 if (ret) {
275 err = 0;
276 goto exit;
277 }
278
279 /* Event on the registration socket */
280 if (pollfd == sock) {
281 if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) {
282 ERR("Health socket poll error");
283 goto error;
284 }
285 }
286 }
287
288 new_sock = lttcomm_accept_unix_sock(sock);
289 if (new_sock < 0) {
290 goto error;
291 }
292
293 /*
294 * Set the CLOEXEC flag. Return code is useless because either way, the
295 * show must go on.
296 */
297 (void) utils_set_fd_cloexec(new_sock);
298
299 DBG("Receiving data from client for health...");
300 ret = lttcomm_recv_unix_sock(new_sock, (void *)&msg, sizeof(msg));
301 if (ret <= 0) {
302 DBG("Nothing recv() from client... continuing");
303 ret = close(new_sock);
304 if (ret) {
305 PERROR("close");
306 }
307 new_sock = -1;
308 continue;
309 }
310
311 rcu_thread_online();
312
313 assert(msg.cmd == HEALTH_CMD_CHECK);
314
6c71277b
MD
315 reply.ret_code = 0;
316 for (i = 0; i < NR_HEALTH_CONSUMERD_TYPES; i++) {
317 /*
318 * health_check_state return 0 if thread is in
319 * error.
320 */
321 if (!health_check_state(health_consumerd, i)) {
322 reply.ret_code |= 1ULL << i;
323 }
5c635c72
MD
324 }
325
6c71277b 326 DBG2("Health check return value %" PRIx64, reply.ret_code);
5c635c72
MD
327
328 ret = send_unix_sock(new_sock, (void *) &reply, sizeof(reply));
329 if (ret < 0) {
330 ERR("Failed to send health data back to client");
331 }
332
333 /* End of transmission */
334 ret = close(new_sock);
335 if (ret) {
336 PERROR("close");
337 }
338 new_sock = -1;
339 }
340
341exit:
342error:
343 if (err) {
344 ERR("Health error occurred in %s", __func__);
345 }
346 DBG("Health check thread dying");
347 unlink(health_unix_sock_path);
348 if (sock >= 0) {
349 ret = close(sock);
350 if (ret) {
351 PERROR("close");
352 }
353 }
354
355 lttng_poll_clean(&events);
356
357 rcu_unregister_thread();
358 return NULL;
359}
This page took 0.036388 seconds and 4 git commands to generate.