Tests: Add test to check shared-memory FD leaks after relayd dies
[lttng-tools.git] / src / lib / lttng-ctl / rotate.cpp
1 /*
2 * Copyright (C) 2017 Julien Desfossez <jdesfossez@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8 #define _LGPL_SOURCE
9 #include <string.h>
10
11 #include <lttng/lttng-error.h>
12 #include <lttng/rotation.h>
13 #include <lttng/location-internal.hpp>
14 #include <lttng/rotate-internal.hpp>
15 #include <common/sessiond-comm/sessiond-comm.hpp>
16 #include <common/macros.hpp>
17
18 #include "lttng-ctl-helper.hpp"
19
20 static
21 enum lttng_rotation_status ask_rotation_info(
22 struct lttng_rotation_handle *rotation_handle,
23 struct lttng_rotation_get_info_return **info)
24 {
25 /* lsm.get_rotation_state.rotation_id */
26 struct lttcomm_session_msg lsm;
27 enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
28 int ret;
29
30 if (!rotation_handle || !info) {
31 status = LTTNG_ROTATION_STATUS_INVALID;
32 goto end;
33 }
34
35 memset(&lsm, 0, sizeof(lsm));
36 lsm.cmd_type = LTTNG_ROTATION_GET_INFO;
37 lsm.u.get_rotation_info.rotation_id = rotation_handle->rotation_id;
38
39 ret = lttng_strncpy(lsm.session.name, rotation_handle->session_name,
40 sizeof(lsm.session.name));
41 if (ret) {
42 status = LTTNG_ROTATION_STATUS_INVALID;
43 goto end;
44 }
45
46 ret = lttng_ctl_ask_sessiond(&lsm, (void **) info);
47 if (ret < 0) {
48 status = LTTNG_ROTATION_STATUS_ERROR;
49 goto end;
50 }
51 end:
52 return status;
53
54 }
55
56 static
57 struct lttng_trace_archive_location *
58 create_trace_archive_location_from_get_info(
59 const struct lttng_rotation_get_info_return *info)
60 {
61 struct lttng_trace_archive_location *location;
62
63 switch (info->location_type) {
64 case LTTNG_TRACE_ARCHIVE_LOCATION_TYPE_LOCAL:
65 location = lttng_trace_archive_location_local_create(
66 info->location.local.absolute_path);
67 break;
68 case LTTNG_TRACE_ARCHIVE_LOCATION_TYPE_RELAY:
69 location = lttng_trace_archive_location_relay_create(
70 info->location.relay.host,
71 (lttng_trace_archive_location_relay_protocol_type) info->location.relay.protocol,
72 info->location.relay.ports.control,
73 info->location.relay.ports.data,
74 info->location.relay.relative_path);
75 break;
76 default:
77 location = NULL;
78 break;
79 }
80 return location;
81 }
82
83 enum lttng_rotation_status lttng_rotation_handle_get_state(
84 struct lttng_rotation_handle *rotation_handle,
85 enum lttng_rotation_state *state)
86 {
87 enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
88 struct lttng_rotation_get_info_return *info = NULL;
89
90 if (!rotation_handle || !state) {
91 status = LTTNG_ROTATION_STATUS_INVALID;
92 goto end;
93 }
94
95 status = ask_rotation_info(rotation_handle, &info);
96 if (status != LTTNG_ROTATION_STATUS_OK) {
97 goto end;
98 }
99
100 *state = (enum lttng_rotation_state) info->status;
101 if (rotation_handle->archive_location ||
102 *state != LTTNG_ROTATION_STATE_COMPLETED) {
103 /*
104 * The path is only provided by the sessiond once
105 * the session rotation is completed, but not expired.
106 */
107 goto end;
108 }
109
110 /*
111 * Cache the location since the rotation may expire before the user
112 * has a chance to query it.
113 */
114 rotation_handle->archive_location =
115 create_trace_archive_location_from_get_info(info);
116 if (!rotation_handle->archive_location) {
117 status = LTTNG_ROTATION_STATUS_ERROR;
118 goto end;
119 }
120 end:
121 free(info);
122 return status;
123 }
124
125 enum lttng_rotation_status lttng_rotation_handle_get_archive_location(
126 struct lttng_rotation_handle *rotation_handle,
127 const struct lttng_trace_archive_location **location)
128 {
129 enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
130 struct lttng_rotation_get_info_return *info = NULL;
131
132 if (!rotation_handle || !location) {
133 status = LTTNG_ROTATION_STATUS_INVALID;
134 goto end;
135 }
136
137 /* Use the cached location we got from a previous query. */
138 if (rotation_handle->archive_location) {
139 *location = rotation_handle->archive_location;
140 goto end;
141 }
142
143 status = ask_rotation_info(rotation_handle, &info);
144 if (status != LTTNG_ROTATION_STATUS_OK) {
145 goto end;
146 }
147
148 if ((enum lttng_rotation_state) info->status !=
149 LTTNG_ROTATION_STATE_COMPLETED) {
150 status = LTTNG_ROTATION_STATUS_UNAVAILABLE;
151 goto end;
152 }
153
154 rotation_handle->archive_location =
155 create_trace_archive_location_from_get_info(info);
156 if (!rotation_handle->archive_location) {
157 status = LTTNG_ROTATION_STATUS_ERROR;
158 goto end;
159 }
160 end:
161 free(info);
162 return status;
163 }
164
165 void lttng_rotation_handle_destroy(
166 struct lttng_rotation_handle *rotation_handle)
167 {
168 if (!rotation_handle) {
169 return;
170 }
171 lttng_trace_archive_location_put(rotation_handle->archive_location);
172 free(rotation_handle);
173 }
174
175 static
176 int init_rotation_handle(struct lttng_rotation_handle *rotation_handle,
177 const char *session_name,
178 struct lttng_rotate_session_return *rotate_return)
179 {
180 int ret;
181
182 ret = lttng_strncpy(rotation_handle->session_name, session_name,
183 sizeof(rotation_handle->session_name));
184 if (ret) {
185 goto end;
186 }
187
188 rotation_handle->rotation_id = rotate_return->rotation_id;
189 end:
190 return ret;
191 }
192
193 /*
194 * Rotate the output folder of the session.
195 *
196 * Return 0 on success else a negative LTTng error code.
197 */
198 int lttng_rotate_session(const char *session_name,
199 struct lttng_rotation_immediate_descriptor *descriptor __attribute__((unused)),
200 struct lttng_rotation_handle **rotation_handle)
201 {
202 struct lttcomm_session_msg lsm;
203 struct lttng_rotate_session_return *rotate_return = NULL;
204 int ret;
205 size_t session_name_len;
206
207 if (!session_name) {
208 ret = -LTTNG_ERR_INVALID;
209 goto end;
210 }
211
212 session_name_len = strlen(session_name);
213 if (session_name_len >= sizeof(lsm.session.name) ||
214 session_name_len >= member_sizeof(struct lttng_rotation_handle, session_name)) {
215 ret = -LTTNG_ERR_INVALID;
216 goto end;
217 }
218
219 memset(&lsm, 0, sizeof(lsm));
220 lsm.cmd_type = LTTNG_ROTATE_SESSION;
221
222 ret = lttng_strncpy(lsm.session.name, session_name,
223 sizeof(lsm.session.name));
224 /* Source length already validated. */
225 LTTNG_ASSERT(ret == 0);
226
227 ret = lttng_ctl_ask_sessiond(&lsm, (void **) &rotate_return);
228 if (ret <= 0) {
229 *rotation_handle = NULL;
230 goto end;
231 }
232
233 *rotation_handle = zmalloc<lttng_rotation_handle>();
234 if (!*rotation_handle) {
235 ret = -LTTNG_ERR_NOMEM;
236 goto end;
237 }
238
239 init_rotation_handle(*rotation_handle, session_name, rotate_return);
240
241 ret = 0;
242
243 end:
244 free(rotate_return);
245 return ret;
246 }
247
248 /*
249 * Update the automatic rotation parameters.
250 * 'add' as true enables the provided schedule, false removes the shedule.
251 *
252 * The external API makes it appear as though arbitrary schedules can
253 * be added or removed at will. However, the session daemon is
254 * currently limited to one schedule per type (per session).
255 *
256 * The additional flexibility of the public API is offered for future
257 * rotation schedules that could indicate more precise criteria than
258 * size and time (e.g. a domain) where it could make sense to add
259 * multiple schedules of a given type to a session.
260 *
261 * Hence, the exact schedule that the user wishes to remove (and not
262 * just its type) must be passed so that the session daemon can
263 * validate that is exists before clearing it.
264 */
265 static
266 enum lttng_rotation_status lttng_rotation_update_schedule(
267 const char *session_name,
268 const struct lttng_rotation_schedule *schedule,
269 bool add)
270 {
271 struct lttcomm_session_msg lsm;
272 enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
273 int ret;
274
275 if (!session_name || !schedule) {
276 status = LTTNG_ROTATION_STATUS_INVALID;
277 goto end;
278 }
279
280 if (strlen(session_name) >= sizeof(lsm.session.name)) {
281 status = LTTNG_ROTATION_STATUS_INVALID;
282 goto end;
283 }
284
285 memset(&lsm, 0, sizeof(lsm));
286 lsm.cmd_type = LTTNG_ROTATION_SET_SCHEDULE;
287 ret = lttng_strncpy(lsm.session.name, session_name,
288 sizeof(lsm.session.name));
289 /* Source length already validated. */
290 LTTNG_ASSERT(ret == 0);
291
292 lsm.u.rotation_set_schedule.type = (uint32_t) schedule->type;
293 switch (schedule->type) {
294 case LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD:
295 {
296 uint64_t threshold;
297
298 status = lttng_rotation_schedule_size_threshold_get_threshold(
299 schedule, &threshold);
300 if (status != LTTNG_ROTATION_STATUS_OK) {
301 if (status == LTTNG_ROTATION_STATUS_UNAVAILABLE) {
302 status = LTTNG_ROTATION_STATUS_INVALID;
303 }
304 goto end;
305 }
306 lsm.u.rotation_set_schedule.value = threshold;
307 lsm.u.rotation_set_schedule.set = !!add;
308 break;
309 }
310 case LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC:
311 {
312 uint64_t period;
313
314 status = lttng_rotation_schedule_periodic_get_period(
315 schedule, &period);
316 if (status != LTTNG_ROTATION_STATUS_OK) {
317 if (status == LTTNG_ROTATION_STATUS_UNAVAILABLE) {
318 status = LTTNG_ROTATION_STATUS_INVALID;
319 }
320 goto end;
321 }
322 lsm.u.rotation_set_schedule.value = period;
323 lsm.u.rotation_set_schedule.set = !!add;
324 break;
325 }
326 default:
327 status = LTTNG_ROTATION_STATUS_INVALID;
328 goto end;
329 }
330
331 ret = lttng_ctl_ask_sessiond(&lsm, NULL);
332 if (ret >= 0) {
333 goto end;
334 }
335
336 switch (-ret) {
337 case LTTNG_ERR_ROTATION_SCHEDULE_SET:
338 status = LTTNG_ROTATION_STATUS_SCHEDULE_ALREADY_SET;
339 break;
340 case LTTNG_ERR_ROTATION_SCHEDULE_NOT_SET:
341 status = LTTNG_ROTATION_STATUS_INVALID;
342 break;
343 default:
344 status = LTTNG_ROTATION_STATUS_ERROR;
345 }
346 end:
347 return status;
348 }
349
350 static
351 struct lttng_rotation_schedules *lttng_rotation_schedules_create(void)
352 {
353 return zmalloc<lttng_rotation_schedules>();
354 }
355
356 static
357 void lttng_schedules_add(struct lttng_rotation_schedules *schedules,
358 struct lttng_rotation_schedule *schedule)
359 {
360 schedules->schedules[schedules->count++] = schedule;
361 }
362
363 static
364 int get_schedules(const char *session_name,
365 struct lttng_rotation_schedules **_schedules)
366 {
367 int ret;
368 struct lttcomm_session_msg lsm;
369 struct lttng_session_list_schedules_return *schedules_comm = NULL;
370 struct lttng_rotation_schedules *schedules = NULL;
371 struct lttng_rotation_schedule *periodic = NULL, *size = NULL;
372
373 if (!session_name) {
374 ret = -LTTNG_ERR_INVALID;
375 goto end;
376 }
377
378 memset(&lsm, 0, sizeof(lsm));
379 lsm.cmd_type = LTTNG_SESSION_LIST_ROTATION_SCHEDULES;
380 ret = lttng_strncpy(lsm.session.name, session_name,
381 sizeof(lsm.session.name));
382 if (ret) {
383 ret = -LTTNG_ERR_INVALID;
384 goto end;
385 }
386
387 ret = lttng_ctl_ask_sessiond(&lsm, (void **) &schedules_comm);
388 if (ret < 0) {
389 goto end;
390 }
391
392 schedules = lttng_rotation_schedules_create();
393 if (!schedules) {
394 ret = -LTTNG_ERR_NOMEM;
395 goto end;
396 }
397
398 if (schedules_comm->periodic.set == 1) {
399 enum lttng_rotation_status status;
400
401 periodic = lttng_rotation_schedule_periodic_create();
402 if (!periodic) {
403 ret = -LTTNG_ERR_NOMEM;
404 goto end;
405 }
406
407 status = lttng_rotation_schedule_periodic_set_period(
408 periodic, schedules_comm->periodic.value);
409 if (status != LTTNG_ROTATION_STATUS_OK) {
410 /*
411 * This would imply that the session daemon returned
412 * an invalid periodic rotation schedule value.
413 */
414 ret = -LTTNG_ERR_UNK;
415 goto end;
416 }
417
418 lttng_schedules_add(schedules, periodic);
419 periodic = NULL;
420 }
421
422 if (schedules_comm->size.set == 1) {
423 enum lttng_rotation_status status;
424
425 size = lttng_rotation_schedule_size_threshold_create();
426 if (!size) {
427 ret = -LTTNG_ERR_NOMEM;
428 goto end;
429 }
430
431 status = lttng_rotation_schedule_size_threshold_set_threshold(
432 size, schedules_comm->size.value);
433 if (status != LTTNG_ROTATION_STATUS_OK) {
434 /*
435 * This would imply that the session daemon returned
436 * an invalid size threshold schedule value.
437 */
438 ret = -LTTNG_ERR_UNK;
439 goto end;
440 }
441
442 lttng_schedules_add(schedules, size);
443 size = NULL;
444 }
445
446 ret = LTTNG_OK;
447 end:
448 free(schedules_comm);
449 free(periodic);
450 free(size);
451 *_schedules = schedules;
452 return ret;
453 }
454
455 enum lttng_rotation_schedule_type lttng_rotation_schedule_get_type(
456 const struct lttng_rotation_schedule *schedule)
457 {
458 return schedule ? schedule->type : LTTNG_ROTATION_SCHEDULE_TYPE_UNKNOWN;
459 }
460
461 struct lttng_rotation_schedule *
462 lttng_rotation_schedule_size_threshold_create(void)
463 {
464 struct lttng_rotation_schedule_size_threshold *schedule;
465
466 schedule = zmalloc<lttng_rotation_schedule_size_threshold>();
467 if (!schedule) {
468 goto end;
469 }
470
471 schedule->parent.type = LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD;
472 end:
473 return &schedule->parent;
474 }
475
476 enum lttng_rotation_status
477 lttng_rotation_schedule_size_threshold_get_threshold(
478 const struct lttng_rotation_schedule *schedule,
479 uint64_t *size_threshold_bytes)
480 {
481 enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
482 struct lttng_rotation_schedule_size_threshold *size_schedule;
483
484 if (!schedule || !size_threshold_bytes ||
485 schedule->type != LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD) {
486 status = LTTNG_ROTATION_STATUS_INVALID;
487 goto end;
488 }
489
490 size_schedule = lttng::utils::container_of(schedule,
491 &lttng_rotation_schedule_size_threshold::parent);
492 if (size_schedule->size.set) {
493 *size_threshold_bytes = size_schedule->size.bytes;
494 } else {
495 status = LTTNG_ROTATION_STATUS_UNAVAILABLE;
496 goto end;
497 }
498 end:
499 return status;
500 }
501
502 enum lttng_rotation_status
503 lttng_rotation_schedule_size_threshold_set_threshold(
504 struct lttng_rotation_schedule *schedule,
505 uint64_t size_threshold_bytes)
506 {
507 enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
508 struct lttng_rotation_schedule_size_threshold *size_schedule;
509
510 if (!schedule || size_threshold_bytes == 0 ||
511 size_threshold_bytes == -1ULL ||
512 schedule->type != LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD) {
513 status = LTTNG_ROTATION_STATUS_INVALID;
514 goto end;
515 }
516
517 size_schedule = lttng::utils::container_of(schedule,
518 &lttng_rotation_schedule_size_threshold::parent);
519 size_schedule->size.bytes = size_threshold_bytes;
520 size_schedule->size.set = true;
521 end:
522 return status;
523 }
524
525 struct lttng_rotation_schedule *
526 lttng_rotation_schedule_periodic_create(void)
527 {
528 struct lttng_rotation_schedule_periodic *schedule;
529
530 schedule = zmalloc<lttng_rotation_schedule_periodic>();
531 if (!schedule) {
532 goto end;
533 }
534
535 schedule->parent.type = LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC;
536 end:
537 return &schedule->parent;
538 }
539
540 enum lttng_rotation_status
541 lttng_rotation_schedule_periodic_get_period(
542 const struct lttng_rotation_schedule *schedule,
543 uint64_t *period_us)
544 {
545 enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
546 struct lttng_rotation_schedule_periodic *periodic_schedule;
547
548 if (!schedule || !period_us ||
549 schedule->type != LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC) {
550 status = LTTNG_ROTATION_STATUS_INVALID;
551 goto end;
552 }
553
554 periodic_schedule = lttng::utils::container_of(schedule,
555 &lttng_rotation_schedule_periodic::parent);
556 if (periodic_schedule->period.set) {
557 *period_us = periodic_schedule->period.us;
558 } else {
559 status = LTTNG_ROTATION_STATUS_UNAVAILABLE;
560 goto end;
561 }
562 end:
563 return status;
564 }
565
566 enum lttng_rotation_status
567 lttng_rotation_schedule_periodic_set_period(
568 struct lttng_rotation_schedule *schedule,
569 uint64_t period_us)
570 {
571 enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
572 struct lttng_rotation_schedule_periodic *periodic_schedule;
573
574 if (!schedule || period_us == 0 || period_us == -1ULL ||
575 schedule->type != LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC) {
576 status = LTTNG_ROTATION_STATUS_INVALID;
577 goto end;
578 }
579
580 periodic_schedule = lttng::utils::container_of(schedule,
581 &lttng_rotation_schedule_periodic::parent);
582 periodic_schedule->period.us = period_us;
583 periodic_schedule->period.set = true;
584 end:
585 return status;
586 }
587
588 void lttng_rotation_schedule_destroy(struct lttng_rotation_schedule *schedule)
589 {
590 if (!schedule) {
591 return;
592 }
593 free(schedule);
594 }
595
596 void lttng_rotation_schedules_destroy(
597 struct lttng_rotation_schedules *schedules)
598 {
599 unsigned int i;
600
601 if (!schedules) {
602 return;
603 }
604
605 for (i = 0; i < schedules->count; i++) {
606 lttng_rotation_schedule_destroy(schedules->schedules[i]);
607 }
608 free(schedules);
609 }
610
611
612 enum lttng_rotation_status lttng_rotation_schedules_get_count(
613 const struct lttng_rotation_schedules *schedules,
614 unsigned int *count)
615 {
616 enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
617
618 if (!schedules || !count) {
619 status = LTTNG_ROTATION_STATUS_INVALID;
620 goto end;
621 }
622
623 *count = schedules->count;
624 end:
625 return status;
626 }
627
628 const struct lttng_rotation_schedule *lttng_rotation_schedules_get_at_index(
629 const struct lttng_rotation_schedules *schedules,
630 unsigned int index)
631 {
632 const struct lttng_rotation_schedule *schedule = NULL;
633
634 if (!schedules || index >= schedules->count) {
635 goto end;
636 }
637
638 schedule = schedules->schedules[index];
639 end:
640 return schedule;
641 }
642
643 enum lttng_rotation_status lttng_session_add_rotation_schedule(
644 const char *session_name,
645 const struct lttng_rotation_schedule *schedule)
646 {
647 return lttng_rotation_update_schedule(session_name, schedule, true);
648 }
649
650 enum lttng_rotation_status lttng_session_remove_rotation_schedule(
651 const char *session_name,
652 const struct lttng_rotation_schedule *schedule)
653 {
654 return lttng_rotation_update_schedule(session_name, schedule, false);
655 }
656
657 int lttng_session_list_rotation_schedules(
658 const char *session_name,
659 struct lttng_rotation_schedules **schedules)
660 {
661 return get_schedules(session_name, schedules);
662 }
This page took 0.04207 seconds and 4 git commands to generate.