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