Clean-up: liblttng-ctl: fix two trivial -Wshadow errors
[lttng-tools.git] / src / lib / lttng-ctl / destruction-handle.c
CommitLineData
3e3665b8 1/*
ab5be9fa 2 * Copyright (C) 2019 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3e3665b8 3 *
ab5be9fa 4 * SPDX-License-Identifier: LGPL-2.1-only
3e3665b8 5 *
3e3665b8
JG
6 */
7
8#include <lttng/destruction-handle.h>
9#include <lttng/rotation.h>
10
11#include <common/optional.h>
12#include <common/compat/poll.h>
13#include <common/compat/time.h>
14#include <common/macros.h>
15#include <common/compat/poll.h>
16#include <common/dynamic-buffer.h>
17#include <common/buffer-view.h>
18#include <common/sessiond-comm/sessiond-comm.h>
19#include <lttng/location-internal.h>
20#include "lttng-ctl-helper.h"
21
22#include <stdbool.h>
23
24enum communication_state {
25 COMMUNICATION_STATE_RECEIVE_LTTNG_MSG,
26 COMMUNICATION_STATE_RECEIVE_COMMAND_HEADER,
27 COMMUNICATION_STATE_RECEIVE_PAYLOAD,
28 COMMUNICATION_STATE_END,
29 COMMUNICATION_STATE_ERROR,
30};
31
32struct lttng_destruction_handle {
33 LTTNG_OPTIONAL(enum lttng_error_code) destruction_return_code;
34 LTTNG_OPTIONAL(enum lttng_rotation_state) rotation_state;
35 struct lttng_trace_archive_location *location;
36 struct {
37 int socket;
38 struct lttng_poll_event events;
39 size_t bytes_left_to_receive;
40 enum communication_state state;
41 struct lttng_dynamic_buffer buffer;
42 LTTNG_OPTIONAL(size_t) data_size;
43 } communication;
44};
45
46void lttng_destruction_handle_destroy(struct lttng_destruction_handle *handle)
47{
48 int ret;
49
50 if (!handle) {
51 return;
52 }
53
54 if (handle->communication.socket >= 0) {
55 ret = close(handle->communication.socket);
56 if (ret) {
57 PERROR("Failed to close lttng-sessiond command socket");
58 }
96c5e4c3
JG
59 }
60 lttng_poll_clean(&handle->communication.events);
3e3665b8
JG
61 lttng_dynamic_buffer_reset(&handle->communication.buffer);
62 lttng_trace_archive_location_destroy(handle->location);
63 free(handle);
64}
65
66static
67struct lttng_destruction_handle *lttng_destruction_handle_create(
68 int sessiond_socket)
69{
70 int ret;
71 struct lttng_destruction_handle *handle = zmalloc(sizeof(*handle));
72
73 if (!handle) {
74 goto end;
75 }
76 lttng_dynamic_buffer_init(&handle->communication.buffer);
77 handle->communication.socket = sessiond_socket;
78 ret = lttng_poll_create(&handle->communication.events, 1, 0);
79 if (ret) {
80 goto error;
81 }
82
83 ret = lttng_poll_add(&handle->communication.events, sessiond_socket,
84 LPOLLIN | LPOLLHUP | LPOLLRDHUP | LPOLLERR);
96c5e4c3 85 if (ret) {
3e3665b8 86 goto error;
96c5e4c3 87 }
3e3665b8
JG
88
89 handle->communication.bytes_left_to_receive =
90 sizeof(struct lttcomm_lttng_msg);
91 handle->communication.state = COMMUNICATION_STATE_RECEIVE_LTTNG_MSG;
92end:
93 return handle;
94error:
95 lttng_destruction_handle_destroy(handle);
96 return NULL;
97}
98
99static
100int handle_state_transition(struct lttng_destruction_handle *handle)
101{
102 int ret = 0;
103
104 assert(handle->communication.bytes_left_to_receive == 0);
105
106 switch (handle->communication.state) {
107 case COMMUNICATION_STATE_RECEIVE_LTTNG_MSG:
108 {
109 const struct lttcomm_lttng_msg *msg =
110 (typeof(msg)) handle->communication.buffer.data;
111
112 LTTNG_OPTIONAL_SET(&handle->destruction_return_code,
113 (enum lttng_error_code) msg->ret_code);
114 if (handle->destruction_return_code.value != LTTNG_OK) {
115 handle->communication.state = COMMUNICATION_STATE_END;
116 break;
117 } else if (msg->cmd_header_size != sizeof(struct lttcomm_session_destroy_command_header) ||
118 msg->data_size > DEFAULT_MAX_TRACE_ARCHIVE_LOCATION_PAYLOAD_SIZE) {
119 handle->communication.state = COMMUNICATION_STATE_ERROR;
120 ret = -1;
121 break;
122 }
123
124 handle->communication.state =
125 COMMUNICATION_STATE_RECEIVE_COMMAND_HEADER;
126 handle->communication.bytes_left_to_receive =
127 msg->cmd_header_size;
128 LTTNG_OPTIONAL_SET(&handle->communication.data_size,
129 msg->data_size);
130 ret = lttng_dynamic_buffer_set_size(
131 &handle->communication.buffer, 0);
132 assert(!ret);
133 break;
134 }
135 case COMMUNICATION_STATE_RECEIVE_COMMAND_HEADER:
136 {
137 const struct lttcomm_session_destroy_command_header *hdr =
138 (typeof(hdr)) handle->communication.buffer.data;
139
140 LTTNG_OPTIONAL_SET(&handle->rotation_state,
141 (enum lttng_rotation_state) hdr->rotation_state);
142 switch (handle->rotation_state.value) {
143 case LTTNG_ROTATION_STATE_COMPLETED:
144 handle->communication.state =
145 COMMUNICATION_STATE_RECEIVE_PAYLOAD;
146 handle->communication.bytes_left_to_receive =
147 LTTNG_OPTIONAL_GET(handle->communication.data_size);
148 break;
149 case LTTNG_ROTATION_STATE_ERROR:
150 case LTTNG_ROTATION_STATE_NO_ROTATION:
151 handle->communication.state = COMMUNICATION_STATE_END;
152 break;
153 default:
154 handle->communication.state = COMMUNICATION_STATE_ERROR;
155 ret = -1;
156 break;
157 }
158 break;
159 }
160 case COMMUNICATION_STATE_RECEIVE_PAYLOAD:
161 {
162 ssize_t location_ret;
163 struct lttng_trace_archive_location *location;
164 const struct lttng_buffer_view view =
165 lttng_buffer_view_from_dynamic_buffer(
166 &handle->communication.buffer, 0, -1);
167
168 location_ret = lttng_trace_archive_location_create_from_buffer(
169 &view, &location);
170 if (location_ret < 0) {
171 ERR("Failed to deserialize trace archive location");
172 handle->communication.state = COMMUNICATION_STATE_ERROR;
173 ret = -1;
174 break;
175 } else {
176 handle->location = location;
177 handle->communication.state = COMMUNICATION_STATE_END;
178 }
179 break;
180 }
181 default:
182 abort();
183 }
184
185 /* Clear reception buffer on state transition. */
186 if (lttng_dynamic_buffer_set_size(&handle->communication.buffer, 0)) {
187 abort();
188 }
189 return ret;
190}
191
192static
193int handle_incoming_data(struct lttng_destruction_handle *handle)
194{
195 int ret;
196 ssize_t comm_ret;
197 const size_t original_buffer_size = handle->communication.buffer.size;
198
199 /* Reserve space for reception. */
200 ret = lttng_dynamic_buffer_set_size(&handle->communication.buffer,
201 original_buffer_size + handle->communication.bytes_left_to_receive);
202 if (ret) {
203 goto end;
204 }
205
206 comm_ret = lttcomm_recv_unix_sock(handle->communication.socket,
207 handle->communication.buffer.data + original_buffer_size,
208 handle->communication.bytes_left_to_receive);
209 if (comm_ret <= 0) {
210 ret = -1;
211 goto end;
212 }
213
214 handle->communication.bytes_left_to_receive -= comm_ret;
215 if (handle->communication.bytes_left_to_receive == 0) {
216 ret = handle_state_transition(handle);
217 } else {
218 ret = lttng_dynamic_buffer_set_size(
219 &handle->communication.buffer,
220 original_buffer_size + comm_ret);
221 }
222end:
223 return ret;
224}
225
226enum lttng_destruction_handle_status
227lttng_destruction_handle_wait_for_completion(
228 struct lttng_destruction_handle *handle, int timeout_ms)
229{
3e3665b8
JG
230 enum lttng_destruction_handle_status status;
231 unsigned long time_left_ms = 0;
232 const bool has_timeout = timeout_ms > 0;
96c5e4c3 233 struct timespec initial_time;
3e3665b8 234
0f7e4628
JG
235 if (!handle) {
236 status = LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID;
237 goto end;
238 }
239
96c5e4c3 240 if (handle->communication.state == COMMUNICATION_STATE_ERROR) {
3e3665b8
JG
241 status = LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR;
242 goto end;
243 } else if (handle->communication.state == COMMUNICATION_STATE_END) {
244 status = LTTNG_DESTRUCTION_HANDLE_STATUS_COMPLETED;
245 goto end;
246 }
96c5e4c3 247 if (has_timeout) {
bf3683d0 248 int ret = lttng_clock_gettime(CLOCK_MONOTONIC, &initial_time);
3e3665b8
JG
249 if (ret) {
250 status = LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR;
251 goto end;
252 }
253 time_left_ms = (unsigned long) timeout_ms;
96c5e4c3 254 }
3e3665b8 255
96c5e4c3 256 while (handle->communication.state != COMMUNICATION_STATE_END &&
3e3665b8
JG
257 (time_left_ms || !has_timeout)) {
258 int ret;
259 uint32_t revents;
96c5e4c3 260 struct timespec current_time, diff;
3e3665b8
JG
261 unsigned long diff_ms;
262
96c5e4c3 263 ret = lttng_poll_wait(&handle->communication.events,
3e3665b8 264 has_timeout ? time_left_ms : -1);
96c5e4c3 265 if (ret == 0) {
3e3665b8
JG
266 /* timeout */
267 break;
268 } else if (ret < 0) {
269 status = LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR;
270 goto end;
271 }
272
273 /* The sessiond connection socket is the only monitored fd. */
274 revents = LTTNG_POLL_GETEV(&handle->communication.events, 0);
275 if (revents & LPOLLIN) {
276 ret = handle_incoming_data(handle);
277 if (ret) {
278 handle->communication.state =
279 COMMUNICATION_STATE_ERROR;
280 status = LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR;
281 goto end;
282 }
283 } else {
284 handle->communication.state = COMMUNICATION_STATE_ERROR;
285 status = LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR;
286 goto end;
287 }
288 if (!has_timeout) {
289 continue;
290 }
291
292 ret = lttng_clock_gettime(CLOCK_MONOTONIC, &current_time);
293 if (ret) {
294 status = LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR;
295 goto end;
296 }
297 diff = timespec_abs_diff(initial_time, current_time);
298 ret = timespec_to_ms(diff, &diff_ms);
299 if (ret) {
300 ERR("Failed to compute elapsed time while waiting for completion");
301 status = LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR;
302 goto end;
303 }
304 DBG("%lums elapsed while waiting for session destruction completion",
305 diff_ms);
306 diff_ms = max_t(unsigned long, diff_ms, 1);
307 diff_ms = min_t(unsigned long, diff_ms, time_left_ms);
308 time_left_ms -= diff_ms;
309 }
310
311 status = handle->communication.state == COMMUNICATION_STATE_END ?
312 LTTNG_DESTRUCTION_HANDLE_STATUS_COMPLETED :
313 LTTNG_DESTRUCTION_HANDLE_STATUS_TIMEOUT;
314end:
315 return status;
316}
317
318enum lttng_destruction_handle_status
319lttng_destruction_handle_get_rotation_state(
320 const struct lttng_destruction_handle *handle,
321 enum lttng_rotation_state *rotation_state)
322{
323 enum lttng_destruction_handle_status status =
324 LTTNG_DESTRUCTION_HANDLE_STATUS_OK;
325
0f7e4628
JG
326 if (!handle || !rotation_state) {
327 status = LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID;
328 goto end;
329 }
330
3e3665b8
JG
331 if (!handle->rotation_state.is_set) {
332 status = LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID;
333 goto end;
334 }
335 *rotation_state = handle->rotation_state.value;
336end:
337 return status;
338}
339
340enum lttng_destruction_handle_status
341lttng_destruction_handle_get_archive_location(
342 const struct lttng_destruction_handle *handle,
343 const struct lttng_trace_archive_location **location)
344{
345 enum lttng_destruction_handle_status status =
346 LTTNG_DESTRUCTION_HANDLE_STATUS_OK;
347
0f7e4628
JG
348 if (!handle || !location) {
349 status = LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID;
350 goto end;
351 }
352
3e3665b8
JG
353 if (!handle->location) {
354 status = LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID;
355 goto end;
356 }
357 *location = handle->location;
358end:
359 return status;
360}
361
362enum lttng_destruction_handle_status
363lttng_destruction_handle_get_result(
364 const struct lttng_destruction_handle *handle,
365 enum lttng_error_code *result)
366{
367 enum lttng_destruction_handle_status status =
368 LTTNG_DESTRUCTION_HANDLE_STATUS_OK;
369
0f7e4628
JG
370 if (!handle || !result) {
371 status = LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID;
372 goto end;
373 }
374
3e3665b8
JG
375 if (!handle->destruction_return_code.is_set) {
376 status = LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID;
377 goto end;
378 }
379 *result = handle->destruction_return_code.value;
380end:
381 return status;
382}
383
384enum lttng_error_code lttng_destroy_session_ext(const char *session_name,
385 struct lttng_destruction_handle **_handle)
386{
387 int ret;
388 ssize_t comm_ret;
389 enum lttng_error_code ret_code = LTTNG_OK;
96c5e4c3 390 struct lttcomm_session_msg lsm = {
3e3665b8
JG
391 .cmd_type = LTTNG_DESTROY_SESSION,
392 };
393 int sessiond_socket = -1;
394 struct lttng_destruction_handle *handle = NULL;
395
1e2bb0af 396 if (!session_name) {
0f7e4628
JG
397 ret_code = LTTNG_ERR_INVALID;
398 goto error;
399 }
400
3e3665b8
JG
401 ret = lttng_strncpy(lsm.session.name, session_name,
402 sizeof(lsm.session.name));
403 if (ret) {
404 ret_code = LTTNG_ERR_INVALID;
405 goto error;
406 }
407
408 ret = connect_sessiond();
409 if (ret < 0) {
410 ret_code = LTTNG_ERR_NO_SESSIOND;
411 goto error;
412 } else {
413 sessiond_socket = ret;
414 }
415
416 handle = lttng_destruction_handle_create(sessiond_socket);
417 if (!handle) {
418 ret_code = LTTNG_ERR_NOMEM;
419 goto error;
420 }
421
ee98f686 422 comm_ret = lttcomm_send_creds_unix_sock(sessiond_socket, &lsm, sizeof(lsm));
3e3665b8
JG
423 if (comm_ret < 0) {
424 ret_code = LTTNG_ERR_FATAL;
425 goto error;
426 }
427 sessiond_socket = -1;
428
429 /* Transfer the handle to the caller. */
430 if (_handle) {
431 *_handle = handle;
432 handle = NULL;
433 }
434error:
435 if (sessiond_socket >= 0) {
436 ret = close(sessiond_socket);
b6d816c5
JG
437 if (ret < 0) {
438 PERROR("Failed to close the LTTng session daemon connection socket");
439 }
3e3665b8
JG
440 }
441 if (handle) {
442 lttng_destruction_handle_destroy(handle);
443 }
444 return ret_code;
445}
This page took 0.045409 seconds and 4 git commands to generate.