docs: Add supported versions and fix-backport policy
[lttng-tools.git] / src / lib / lttng-ctl / clear.cpp
CommitLineData
f2c1f0d4 1/*
ab5be9fa
MJ
2 * Copyright (C) 2019 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 * Copyright (C) 2019 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
f2c1f0d4 4 *
ab5be9fa 5 * SPDX-License-Identifier: LGPL-2.1-only
f2c1f0d4 6 *
f2c1f0d4
MD
7 */
8
9#define _LGPL_SOURCE
28ab034a 10#include "lttng-ctl-helper.hpp"
f2c1f0d4 11
28ab034a 12#include <common/buffer-view.hpp>
c9e313bc
SM
13#include <common/compat/poll.hpp>
14#include <common/dynamic-buffer.hpp>
28ab034a 15#include <common/macros.hpp>
c9e313bc 16#include <common/optional.hpp>
28ab034a 17#include <common/sessiond-comm/sessiond-comm.hpp>
c9e313bc 18
28ab034a
JG
19#include <lttng/clear-handle.h>
20#include <lttng/clear.h>
21#include <lttng/lttng-error.h>
22
23#include <algorithm>
24#include <string.h>
f2c1f0d4
MD
25
26enum communication_state {
27 COMMUNICATION_STATE_RECEIVE_LTTNG_MSG,
28 COMMUNICATION_STATE_RECEIVE_COMMAND_HEADER,
29 COMMUNICATION_STATE_END,
30 COMMUNICATION_STATE_ERROR,
31};
32
33struct lttng_clear_handle {
34 LTTNG_OPTIONAL(enum lttng_error_code) clear_return_code;
35 struct {
36 int socket;
37 struct lttng_poll_event events;
38 size_t bytes_left_to_receive;
39 enum communication_state state;
40 struct lttng_dynamic_buffer buffer;
41 LTTNG_OPTIONAL(size_t) data_size;
42 } communication;
43};
44
45void lttng_clear_handle_destroy(struct lttng_clear_handle *handle)
46{
47 int ret;
48
49 if (!handle) {
50 return;
51 }
52
53 if (handle->communication.socket >= 0) {
54 ret = close(handle->communication.socket);
55 if (ret) {
56 PERROR("Failed to close lttng-sessiond command socket");
57 }
e429da85
JG
58 }
59 lttng_poll_clean(&handle->communication.events);
f2c1f0d4
MD
60 lttng_dynamic_buffer_reset(&handle->communication.buffer);
61 free(handle);
62}
63
28ab034a 64static struct lttng_clear_handle *lttng_clear_handle_create(int sessiond_socket)
f2c1f0d4
MD
65{
66 int ret;
64803277 67 struct lttng_clear_handle *handle = zmalloc<lttng_clear_handle>();
f2c1f0d4
MD
68
69 if (!handle) {
70 goto end;
71 }
72 lttng_dynamic_buffer_init(&handle->communication.buffer);
73 handle->communication.socket = sessiond_socket;
74 ret = lttng_poll_create(&handle->communication.events, 1, 0);
75 if (ret) {
76 goto error;
77 }
78
28ab034a 79 ret = lttng_poll_add(&handle->communication.events, sessiond_socket, LPOLLIN | LPOLLRDHUP);
e429da85 80 if (ret) {
f2c1f0d4 81 goto error;
e429da85 82 }
f2c1f0d4 83
28ab034a 84 handle->communication.bytes_left_to_receive = sizeof(struct lttcomm_lttng_msg);
f2c1f0d4
MD
85 handle->communication.state = COMMUNICATION_STATE_RECEIVE_LTTNG_MSG;
86end:
87 return handle;
88error:
89 lttng_clear_handle_destroy(handle);
cd9adb8b 90 return nullptr;
f2c1f0d4
MD
91}
92
28ab034a 93static int handle_state_transition(struct lttng_clear_handle *handle)
f2c1f0d4
MD
94{
95 int ret = 0;
96
a0377dfe 97 LTTNG_ASSERT(handle->communication.bytes_left_to_receive == 0);
f2c1f0d4
MD
98
99 switch (handle->communication.state) {
100 case COMMUNICATION_STATE_RECEIVE_LTTNG_MSG:
101 {
102 const struct lttcomm_lttng_msg *msg =
28ab034a 103 (typeof(msg)) handle->communication.buffer.data;
f2c1f0d4
MD
104
105 LTTNG_OPTIONAL_SET(&handle->clear_return_code,
28ab034a 106 (enum lttng_error_code) msg->ret_code);
f2c1f0d4
MD
107 if (handle->clear_return_code.value != LTTNG_OK) {
108 handle->communication.state = COMMUNICATION_STATE_END;
109 break;
110 } else if (msg->cmd_header_size != 0 || msg->data_size != 0) {
111 handle->communication.state = COMMUNICATION_STATE_ERROR;
112 ret = -1;
113 break;
114 }
115
116 handle->communication.state = COMMUNICATION_STATE_END;
117 handle->communication.bytes_left_to_receive = 0;
118 LTTNG_OPTIONAL_SET(&handle->communication.data_size, 0);
28ab034a 119 ret = lttng_dynamic_buffer_set_size(&handle->communication.buffer, 0);
a0377dfe 120 LTTNG_ASSERT(!ret);
f2c1f0d4
MD
121 break;
122 }
123 default:
124 abort();
125 }
126
127 /* Clear reception buffer on state transition. */
128 if (lttng_dynamic_buffer_set_size(&handle->communication.buffer, 0)) {
129 abort();
130 }
131 return ret;
132}
133
28ab034a 134static int handle_incoming_data(struct lttng_clear_handle *handle)
f2c1f0d4
MD
135{
136 int ret;
137 ssize_t comm_ret;
138 const size_t original_buffer_size = handle->communication.buffer.size;
139
140 /* Reserve space for reception. */
141 ret = lttng_dynamic_buffer_set_size(&handle->communication.buffer,
28ab034a
JG
142 original_buffer_size +
143 handle->communication.bytes_left_to_receive);
f2c1f0d4
MD
144 if (ret) {
145 goto end;
146 }
147
148 comm_ret = lttcomm_recv_unix_sock(handle->communication.socket,
28ab034a
JG
149 handle->communication.buffer.data + original_buffer_size,
150 handle->communication.bytes_left_to_receive);
f2c1f0d4
MD
151 if (comm_ret <= 0) {
152 ret = -1;
153 goto end;
154 }
155
156 handle->communication.bytes_left_to_receive -= comm_ret;
157 if (handle->communication.bytes_left_to_receive == 0) {
158 ret = handle_state_transition(handle);
159 } else {
28ab034a
JG
160 ret = lttng_dynamic_buffer_set_size(&handle->communication.buffer,
161 original_buffer_size + comm_ret);
f2c1f0d4
MD
162 }
163end:
164 return ret;
165}
166
167extern enum lttng_clear_handle_status
28ab034a 168lttng_clear_handle_wait_for_completion(struct lttng_clear_handle *handle, int timeout_ms)
f2c1f0d4 169{
f2c1f0d4
MD
170 enum lttng_clear_handle_status status;
171 unsigned long time_left_ms = 0;
172 const bool has_timeout = timeout_ms > 0;
173 struct timespec initial_time;
174
e429da85 175 if (handle->communication.state == COMMUNICATION_STATE_ERROR) {
f2c1f0d4
MD
176 status = LTTNG_CLEAR_HANDLE_STATUS_ERROR;
177 goto end;
178 } else if (handle->communication.state == COMMUNICATION_STATE_END) {
179 status = LTTNG_CLEAR_HANDLE_STATUS_COMPLETED;
180 goto end;
181 }
e429da85 182 if (has_timeout) {
bf3683d0 183 int ret = lttng_clock_gettime(CLOCK_MONOTONIC, &initial_time);
f2c1f0d4
MD
184 if (ret) {
185 status = LTTNG_CLEAR_HANDLE_STATUS_ERROR;
186 goto end;
187 }
188 time_left_ms = (unsigned long) timeout_ms;
e429da85 189 }
f2c1f0d4 190
e429da85 191 while (handle->communication.state != COMMUNICATION_STATE_END &&
28ab034a 192 (time_left_ms || !has_timeout)) {
f2c1f0d4
MD
193 int ret;
194 uint32_t revents;
e429da85 195 struct timespec current_time, diff;
f2c1f0d4
MD
196 unsigned long diff_ms;
197
e429da85 198 ret = lttng_poll_wait(&handle->communication.events,
28ab034a 199 has_timeout ? time_left_ms : -1);
e429da85 200 if (ret == 0) {
f2c1f0d4
MD
201 /* timeout */
202 break;
203 } else if (ret < 0) {
204 status = LTTNG_CLEAR_HANDLE_STATUS_ERROR;
205 goto end;
206 }
207
208 /* The sessiond connection socket is the only monitored fd. */
209 revents = LTTNG_POLL_GETEV(&handle->communication.events, 0);
210 if (revents & LPOLLIN) {
211 ret = handle_incoming_data(handle);
212 if (ret) {
28ab034a 213 handle->communication.state = COMMUNICATION_STATE_ERROR;
f2c1f0d4
MD
214 status = LTTNG_CLEAR_HANDLE_STATUS_ERROR;
215 goto end;
216 }
217 } else {
218 handle->communication.state = COMMUNICATION_STATE_ERROR;
219 status = LTTNG_CLEAR_HANDLE_STATUS_ERROR;
220 goto end;
221 }
222 if (!has_timeout) {
223 continue;
224 }
225
226 ret = lttng_clock_gettime(CLOCK_MONOTONIC, &current_time);
227 if (ret) {
228 status = LTTNG_CLEAR_HANDLE_STATUS_ERROR;
229 goto end;
230 }
231 diff = timespec_abs_diff(initial_time, current_time);
232 ret = timespec_to_ms(diff, &diff_ms);
233 if (ret) {
234 ERR("Failed to compute elapsed time while waiting for completion");
235 status = LTTNG_CLEAR_HANDLE_STATUS_ERROR;
236 goto end;
237 }
28ab034a 238 DBG("%lums elapsed while waiting for session clear completion", diff_ms);
4bd69c5f
SM
239 diff_ms = std::max(diff_ms, 1UL);
240 diff_ms = std::min(diff_ms, time_left_ms);
f2c1f0d4
MD
241 time_left_ms -= diff_ms;
242 }
243
244 status = handle->communication.state == COMMUNICATION_STATE_END ?
28ab034a
JG
245 LTTNG_CLEAR_HANDLE_STATUS_COMPLETED :
246 LTTNG_CLEAR_HANDLE_STATUS_TIMEOUT;
f2c1f0d4
MD
247end:
248 return status;
249}
250
251extern enum lttng_clear_handle_status
28ab034a
JG
252lttng_clear_handle_get_result(const struct lttng_clear_handle *handle,
253 enum lttng_error_code *result)
f2c1f0d4 254{
28ab034a 255 enum lttng_clear_handle_status status = LTTNG_CLEAR_HANDLE_STATUS_OK;
f2c1f0d4
MD
256
257 if (!handle->clear_return_code.is_set) {
258 status = LTTNG_CLEAR_HANDLE_STATUS_INVALID;
259 goto end;
260 }
261 *result = handle->clear_return_code.value;
262end:
263 return status;
264}
265
266/*
267 * Clear the session
268 */
269enum lttng_error_code lttng_clear_session(const char *session_name,
28ab034a 270 struct lttng_clear_handle **_handle)
f2c1f0d4
MD
271{
272 enum lttng_error_code ret_code = LTTNG_OK;
cd9adb8b 273 struct lttng_clear_handle *handle = nullptr;
f2c1f0d4 274 struct lttcomm_session_msg lsm = {
37a5ef39 275 .cmd_type = LTTCOMM_SESSIOND_COMMAND_CLEAR_SESSION,
1c9a0b0e
MJ
276 .session = {},
277 .domain = {},
278 .u = {},
279 .fd_count = 0,
f2c1f0d4
MD
280 };
281 int sessiond_socket = -1;
282 ssize_t comm_ret;
283 int ret;
284
cd9adb8b 285 if (session_name == nullptr) {
f2c1f0d4
MD
286 ret_code = LTTNG_ERR_INVALID;
287 goto error;
288 }
28ab034a 289 ret = lttng_strncpy(lsm.session.name, session_name, sizeof(lsm.session.name));
f2c1f0d4
MD
290 if (ret) {
291 ret_code = LTTNG_ERR_INVALID;
292 goto error;
293 }
294 ret = connect_sessiond();
295 if (ret < 0) {
296 ret_code = LTTNG_ERR_NO_SESSIOND;
297 goto error;
298 } else {
299 sessiond_socket = ret;
300 }
301 handle = lttng_clear_handle_create(sessiond_socket);
302 if (!handle) {
303 ret_code = LTTNG_ERR_NOMEM;
304 goto error;
305 }
306 comm_ret = lttcomm_send_creds_unix_sock(sessiond_socket, &lsm, sizeof(lsm));
307 if (comm_ret < 0) {
308 ret_code = LTTNG_ERR_FATAL;
309 goto error;
310 }
311 sessiond_socket = -1;
312
313error:
314 /* Transfer the handle to the caller. */
315 if (_handle) {
316 *_handle = handle;
cd9adb8b 317 handle = nullptr;
f2c1f0d4
MD
318 }
319 if (sessiond_socket >= 0) {
320 ret = close(sessiond_socket);
321 if (ret < 0) {
322 PERROR("Failed to close the LTTng session daemon connection socket");
323 }
324 }
325 if (handle) {
326 lttng_clear_handle_destroy(handle);
327 }
328 return ret_code;
329}
This page took 0.060631 seconds and 4 git commands to generate.