2 * Copyright (C) 2017 Julien Desfossez <jdesfossez@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
9 #include "lttng-ctl-helper.hpp"
11 #include <common/macros.hpp>
12 #include <common/sessiond-comm/sessiond-comm.hpp>
14 #include <lttng/location-internal.hpp>
15 #include <lttng/lttng-error.h>
16 #include <lttng/rotate-internal.hpp>
17 #include <lttng/rotation.h>
21 static enum lttng_rotation_status
ask_rotation_info(struct lttng_rotation_handle
*rotation_handle
,
22 struct lttng_rotation_get_info_return
**info
)
24 /* lsm.get_rotation_state.rotation_id */
25 struct lttcomm_session_msg lsm
;
26 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
29 if (!rotation_handle
|| !info
) {
30 status
= LTTNG_ROTATION_STATUS_INVALID
;
34 memset(&lsm
, 0, sizeof(lsm
));
35 lsm
.cmd_type
= LTTCOMM_SESSIOND_COMMAND_ROTATION_GET_INFO
;
36 lsm
.u
.get_rotation_info
.rotation_id
= rotation_handle
->rotation_id
;
39 lsm
.session
.name
, rotation_handle
->session_name
, sizeof(lsm
.session
.name
));
41 status
= LTTNG_ROTATION_STATUS_INVALID
;
45 ret
= lttng_ctl_ask_sessiond(&lsm
, (void **) info
);
47 status
= LTTNG_ROTATION_STATUS_ERROR
;
54 static struct lttng_trace_archive_location
*
55 create_trace_archive_location_from_get_info(const struct lttng_rotation_get_info_return
*info
)
57 struct lttng_trace_archive_location
*location
;
59 switch (info
->location_type
) {
60 case LTTNG_TRACE_ARCHIVE_LOCATION_TYPE_LOCAL
:
61 location
= lttng_trace_archive_location_local_create(
62 info
->location
.local
.absolute_path
);
64 case LTTNG_TRACE_ARCHIVE_LOCATION_TYPE_RELAY
:
65 location
= lttng_trace_archive_location_relay_create(
66 info
->location
.relay
.host
,
67 (lttng_trace_archive_location_relay_protocol_type
)
68 info
->location
.relay
.protocol
,
69 info
->location
.relay
.ports
.control
,
70 info
->location
.relay
.ports
.data
,
71 info
->location
.relay
.relative_path
);
80 enum lttng_rotation_status
81 lttng_rotation_handle_get_state(struct lttng_rotation_handle
*rotation_handle
,
82 enum lttng_rotation_state
*state
)
84 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
85 struct lttng_rotation_get_info_return
*info
= nullptr;
87 if (!rotation_handle
|| !state
) {
88 status
= LTTNG_ROTATION_STATUS_INVALID
;
92 status
= ask_rotation_info(rotation_handle
, &info
);
93 if (status
!= LTTNG_ROTATION_STATUS_OK
) {
97 *state
= (enum lttng_rotation_state
) info
->status
;
98 if (rotation_handle
->archive_location
|| *state
!= LTTNG_ROTATION_STATE_COMPLETED
) {
100 * The path is only provided by the sessiond once
101 * the session rotation is completed, but not expired.
107 * Cache the location since the rotation may expire before the user
108 * has a chance to query it.
110 rotation_handle
->archive_location
= create_trace_archive_location_from_get_info(info
);
111 if (!rotation_handle
->archive_location
) {
112 status
= LTTNG_ROTATION_STATUS_ERROR
;
120 enum lttng_rotation_status
121 lttng_rotation_handle_get_archive_location(struct lttng_rotation_handle
*rotation_handle
,
122 const struct lttng_trace_archive_location
**location
)
124 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
125 struct lttng_rotation_get_info_return
*info
= nullptr;
127 if (!rotation_handle
|| !location
) {
128 status
= LTTNG_ROTATION_STATUS_INVALID
;
132 /* Use the cached location we got from a previous query. */
133 if (rotation_handle
->archive_location
) {
134 *location
= rotation_handle
->archive_location
;
138 status
= ask_rotation_info(rotation_handle
, &info
);
139 if (status
!= LTTNG_ROTATION_STATUS_OK
) {
143 if ((enum lttng_rotation_state
) info
->status
!= LTTNG_ROTATION_STATE_COMPLETED
) {
144 status
= LTTNG_ROTATION_STATUS_UNAVAILABLE
;
148 rotation_handle
->archive_location
= create_trace_archive_location_from_get_info(info
);
149 if (!rotation_handle
->archive_location
) {
150 status
= LTTNG_ROTATION_STATUS_ERROR
;
158 void lttng_rotation_handle_destroy(struct lttng_rotation_handle
*rotation_handle
)
160 if (!rotation_handle
) {
163 lttng_trace_archive_location_put(rotation_handle
->archive_location
);
164 free(rotation_handle
);
167 static int init_rotation_handle(struct lttng_rotation_handle
*rotation_handle
,
168 const char *session_name
,
169 struct lttng_rotate_session_return
*rotate_return
)
174 rotation_handle
->session_name
, session_name
, sizeof(rotation_handle
->session_name
));
179 rotation_handle
->rotation_id
= rotate_return
->rotation_id
;
185 * Rotate the output folder of the session.
187 * Return 0 on success else a negative LTTng error code.
189 int lttng_rotate_session(const char *session_name
,
190 struct lttng_rotation_immediate_descriptor
*descriptor
191 __attribute__((unused
)),
192 struct lttng_rotation_handle
**rotation_handle
)
194 struct lttcomm_session_msg lsm
;
195 struct lttng_rotate_session_return
*rotate_return
= nullptr;
197 size_t session_name_len
;
200 ret
= -LTTNG_ERR_INVALID
;
204 session_name_len
= strlen(session_name
);
205 if (session_name_len
>= sizeof(lsm
.session
.name
) ||
206 session_name_len
>= member_sizeof(struct lttng_rotation_handle
, session_name
)) {
207 ret
= -LTTNG_ERR_INVALID
;
211 memset(&lsm
, 0, sizeof(lsm
));
212 lsm
.cmd_type
= LTTCOMM_SESSIOND_COMMAND_ROTATE_SESSION
;
214 ret
= lttng_strncpy(lsm
.session
.name
, session_name
, sizeof(lsm
.session
.name
));
215 /* Source length already validated. */
216 LTTNG_ASSERT(ret
== 0);
218 ret
= lttng_ctl_ask_sessiond(&lsm
, (void **) &rotate_return
);
220 *rotation_handle
= nullptr;
224 *rotation_handle
= zmalloc
<lttng_rotation_handle
>();
225 if (!*rotation_handle
) {
226 ret
= -LTTNG_ERR_NOMEM
;
230 init_rotation_handle(*rotation_handle
, session_name
, rotate_return
);
240 * Update the automatic rotation parameters.
241 * 'add' as true enables the provided schedule, false removes the shedule.
243 * The external API makes it appear as though arbitrary schedules can
244 * be added or removed at will. However, the session daemon is
245 * currently limited to one schedule per type (per session).
247 * The additional flexibility of the public API is offered for future
248 * rotation schedules that could indicate more precise criteria than
249 * size and time (e.g. a domain) where it could make sense to add
250 * multiple schedules of a given type to a session.
252 * Hence, the exact schedule that the user wishes to remove (and not
253 * just its type) must be passed so that the session daemon can
254 * validate that is exists before clearing it.
256 static enum lttng_rotation_status
lttng_rotation_update_schedule(
257 const char *session_name
, const struct lttng_rotation_schedule
*schedule
, bool add
)
259 struct lttcomm_session_msg lsm
;
260 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
263 if (!session_name
|| !schedule
) {
264 status
= LTTNG_ROTATION_STATUS_INVALID
;
268 if (strlen(session_name
) >= sizeof(lsm
.session
.name
)) {
269 status
= LTTNG_ROTATION_STATUS_INVALID
;
273 memset(&lsm
, 0, sizeof(lsm
));
274 lsm
.cmd_type
= LTTCOMM_SESSIOND_COMMAND_ROTATION_SET_SCHEDULE
;
275 ret
= lttng_strncpy(lsm
.session
.name
, session_name
, sizeof(lsm
.session
.name
));
276 /* Source length already validated. */
277 LTTNG_ASSERT(ret
== 0);
279 lsm
.u
.rotation_set_schedule
.type
= (uint32_t) schedule
->type
;
280 switch (schedule
->type
) {
281 case LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD
:
285 status
= lttng_rotation_schedule_size_threshold_get_threshold(schedule
, &threshold
);
286 if (status
!= LTTNG_ROTATION_STATUS_OK
) {
287 if (status
== LTTNG_ROTATION_STATUS_UNAVAILABLE
) {
288 status
= LTTNG_ROTATION_STATUS_INVALID
;
292 lsm
.u
.rotation_set_schedule
.value
= threshold
;
293 lsm
.u
.rotation_set_schedule
.set
= !!add
;
296 case LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC
:
300 status
= lttng_rotation_schedule_periodic_get_period(schedule
, &period
);
301 if (status
!= LTTNG_ROTATION_STATUS_OK
) {
302 if (status
== LTTNG_ROTATION_STATUS_UNAVAILABLE
) {
303 status
= LTTNG_ROTATION_STATUS_INVALID
;
307 lsm
.u
.rotation_set_schedule
.value
= period
;
308 lsm
.u
.rotation_set_schedule
.set
= !!add
;
312 status
= LTTNG_ROTATION_STATUS_INVALID
;
316 ret
= lttng_ctl_ask_sessiond(&lsm
, nullptr);
322 case LTTNG_ERR_ROTATION_SCHEDULE_SET
:
323 status
= LTTNG_ROTATION_STATUS_SCHEDULE_ALREADY_SET
;
325 case LTTNG_ERR_ROTATION_SCHEDULE_NOT_SET
:
326 status
= LTTNG_ROTATION_STATUS_INVALID
;
329 status
= LTTNG_ROTATION_STATUS_ERROR
;
335 static struct lttng_rotation_schedules
*lttng_rotation_schedules_create()
337 return zmalloc
<lttng_rotation_schedules
>();
340 static void lttng_schedules_add(struct lttng_rotation_schedules
*schedules
,
341 struct lttng_rotation_schedule
*schedule
)
343 schedules
->schedules
[schedules
->count
++] = schedule
;
346 static int get_schedules(const char *session_name
, struct lttng_rotation_schedules
**_schedules
)
349 struct lttcomm_session_msg lsm
;
350 struct lttng_session_list_schedules_return
*schedules_comm
= nullptr;
351 struct lttng_rotation_schedules
*schedules
= nullptr;
352 struct lttng_rotation_schedule
*periodic
= nullptr, *size
= nullptr;
355 ret
= -LTTNG_ERR_INVALID
;
359 memset(&lsm
, 0, sizeof(lsm
));
360 lsm
.cmd_type
= LTTCOMM_SESSIOND_COMMAND_SESSION_LIST_ROTATION_SCHEDULES
;
361 ret
= lttng_strncpy(lsm
.session
.name
, session_name
, sizeof(lsm
.session
.name
));
363 ret
= -LTTNG_ERR_INVALID
;
367 ret
= lttng_ctl_ask_sessiond(&lsm
, (void **) &schedules_comm
);
372 schedules
= lttng_rotation_schedules_create();
374 ret
= -LTTNG_ERR_NOMEM
;
378 if (schedules_comm
->periodic
.set
== 1) {
379 enum lttng_rotation_status status
;
381 periodic
= lttng_rotation_schedule_periodic_create();
383 ret
= -LTTNG_ERR_NOMEM
;
387 status
= lttng_rotation_schedule_periodic_set_period(
388 periodic
, schedules_comm
->periodic
.value
);
389 if (status
!= LTTNG_ROTATION_STATUS_OK
) {
391 * This would imply that the session daemon returned
392 * an invalid periodic rotation schedule value.
394 ret
= -LTTNG_ERR_UNK
;
398 lttng_schedules_add(schedules
, periodic
);
402 if (schedules_comm
->size
.set
== 1) {
403 enum lttng_rotation_status status
;
405 size
= lttng_rotation_schedule_size_threshold_create();
407 ret
= -LTTNG_ERR_NOMEM
;
411 status
= lttng_rotation_schedule_size_threshold_set_threshold(
412 size
, schedules_comm
->size
.value
);
413 if (status
!= LTTNG_ROTATION_STATUS_OK
) {
415 * This would imply that the session daemon returned
416 * an invalid size threshold schedule value.
418 ret
= -LTTNG_ERR_UNK
;
422 lttng_schedules_add(schedules
, size
);
428 free(schedules_comm
);
431 *_schedules
= schedules
;
435 enum lttng_rotation_schedule_type
436 lttng_rotation_schedule_get_type(const struct lttng_rotation_schedule
*schedule
)
438 return schedule
? schedule
->type
: LTTNG_ROTATION_SCHEDULE_TYPE_UNKNOWN
;
441 struct lttng_rotation_schedule
*lttng_rotation_schedule_size_threshold_create(void)
443 struct lttng_rotation_schedule_size_threshold
*schedule
;
445 schedule
= zmalloc
<lttng_rotation_schedule_size_threshold
>();
450 schedule
->parent
.type
= LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD
;
452 return &schedule
->parent
;
455 enum lttng_rotation_status
456 lttng_rotation_schedule_size_threshold_get_threshold(const struct lttng_rotation_schedule
*schedule
,
457 uint64_t *size_threshold_bytes
)
459 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
460 struct lttng_rotation_schedule_size_threshold
*size_schedule
;
462 if (!schedule
|| !size_threshold_bytes
||
463 schedule
->type
!= LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD
) {
464 status
= LTTNG_ROTATION_STATUS_INVALID
;
468 size_schedule
= lttng::utils::container_of(schedule
,
469 <tng_rotation_schedule_size_threshold::parent
);
470 if (size_schedule
->size
.set
) {
471 *size_threshold_bytes
= size_schedule
->size
.bytes
;
473 status
= LTTNG_ROTATION_STATUS_UNAVAILABLE
;
480 enum lttng_rotation_status
481 lttng_rotation_schedule_size_threshold_set_threshold(struct lttng_rotation_schedule
*schedule
,
482 uint64_t size_threshold_bytes
)
484 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
485 struct lttng_rotation_schedule_size_threshold
*size_schedule
;
487 if (!schedule
|| size_threshold_bytes
== 0 || size_threshold_bytes
== -1ULL ||
488 schedule
->type
!= LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD
) {
489 status
= LTTNG_ROTATION_STATUS_INVALID
;
493 size_schedule
= lttng::utils::container_of(schedule
,
494 <tng_rotation_schedule_size_threshold::parent
);
495 size_schedule
->size
.bytes
= size_threshold_bytes
;
496 size_schedule
->size
.set
= true;
501 struct lttng_rotation_schedule
*lttng_rotation_schedule_periodic_create(void)
503 struct lttng_rotation_schedule_periodic
*schedule
;
505 schedule
= zmalloc
<lttng_rotation_schedule_periodic
>();
510 schedule
->parent
.type
= LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC
;
512 return &schedule
->parent
;
515 enum lttng_rotation_status
516 lttng_rotation_schedule_periodic_get_period(const struct lttng_rotation_schedule
*schedule
,
519 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
520 struct lttng_rotation_schedule_periodic
*periodic_schedule
;
522 if (!schedule
|| !period_us
|| schedule
->type
!= LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC
) {
523 status
= LTTNG_ROTATION_STATUS_INVALID
;
528 lttng::utils::container_of(schedule
, <tng_rotation_schedule_periodic::parent
);
529 if (periodic_schedule
->period
.set
) {
530 *period_us
= periodic_schedule
->period
.us
;
532 status
= LTTNG_ROTATION_STATUS_UNAVAILABLE
;
539 enum lttng_rotation_status
540 lttng_rotation_schedule_periodic_set_period(struct lttng_rotation_schedule
*schedule
,
543 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
544 struct lttng_rotation_schedule_periodic
*periodic_schedule
;
546 if (!schedule
|| period_us
== 0 || period_us
== -1ULL ||
547 schedule
->type
!= LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC
) {
548 status
= LTTNG_ROTATION_STATUS_INVALID
;
553 lttng::utils::container_of(schedule
, <tng_rotation_schedule_periodic::parent
);
554 periodic_schedule
->period
.us
= period_us
;
555 periodic_schedule
->period
.set
= true;
560 void lttng_rotation_schedule_destroy(struct lttng_rotation_schedule
*schedule
)
568 void lttng_rotation_schedules_destroy(struct lttng_rotation_schedules
*schedules
)
576 for (i
= 0; i
< schedules
->count
; i
++) {
577 lttng_rotation_schedule_destroy(schedules
->schedules
[i
]);
582 enum lttng_rotation_status
583 lttng_rotation_schedules_get_count(const struct lttng_rotation_schedules
*schedules
,
586 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
588 if (!schedules
|| !count
) {
589 status
= LTTNG_ROTATION_STATUS_INVALID
;
593 *count
= schedules
->count
;
598 const struct lttng_rotation_schedule
*
599 lttng_rotation_schedules_get_at_index(const struct lttng_rotation_schedules
*schedules
,
602 const struct lttng_rotation_schedule
*schedule
= nullptr;
604 if (!schedules
|| index
>= schedules
->count
) {
608 schedule
= schedules
->schedules
[index
];
613 enum lttng_rotation_status
614 lttng_session_add_rotation_schedule(const char *session_name
,
615 const struct lttng_rotation_schedule
*schedule
)
617 return lttng_rotation_update_schedule(session_name
, schedule
, true);
620 enum lttng_rotation_status
621 lttng_session_remove_rotation_schedule(const char *session_name
,
622 const struct lttng_rotation_schedule
*schedule
)
624 return lttng_rotation_update_schedule(session_name
, schedule
, false);
627 int lttng_session_list_rotation_schedules(const char *session_name
,
628 struct lttng_rotation_schedules
**schedules
)
630 return get_schedules(session_name
, schedules
);