2 * Copyright (C) 2017 Julien Desfossez <jdesfossez@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
11 #include <lttng/lttng-error.h>
12 #include <lttng/rotation.h>
13 #include <lttng/location-internal.h>
14 #include <lttng/rotate-internal.h>
15 #include <common/sessiond-comm/sessiond-comm.h>
16 #include <common/macros.h>
18 #include "lttng-ctl-helper.h"
21 enum lttng_rotation_status
ask_rotation_info(
22 struct lttng_rotation_handle
*rotation_handle
,
23 struct lttng_rotation_get_info_return
**info
)
25 /* lsm.get_rotation_state.rotation_id */
26 struct lttcomm_session_msg lsm
;
27 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
30 if (!rotation_handle
|| !info
) {
31 status
= LTTNG_ROTATION_STATUS_INVALID
;
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
;
39 ret
= lttng_strncpy(lsm
.session
.name
, rotation_handle
->session_name
,
40 sizeof(lsm
.session
.name
));
42 status
= LTTNG_ROTATION_STATUS_INVALID
;
46 ret
= lttng_ctl_ask_sessiond(&lsm
, (void **) info
);
48 status
= LTTNG_ROTATION_STATUS_ERROR
;
57 struct lttng_trace_archive_location
*
58 create_trace_archive_location_from_get_info(
59 const struct lttng_rotation_get_info_return
*info
)
61 struct lttng_trace_archive_location
*location
;
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
);
68 case LTTNG_TRACE_ARCHIVE_LOCATION_TYPE_RELAY
:
69 location
= lttng_trace_archive_location_relay_create(
70 info
->location
.relay
.host
,
71 info
->location
.relay
.protocol
,
72 info
->location
.relay
.ports
.control
,
73 info
->location
.relay
.ports
.data
,
74 info
->location
.relay
.relative_path
);
83 enum lttng_rotation_status
lttng_rotation_handle_get_state(
84 struct lttng_rotation_handle
*rotation_handle
,
85 enum lttng_rotation_state
*state
)
87 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
88 struct lttng_rotation_get_info_return
*info
= NULL
;
90 if (!rotation_handle
|| !state
) {
91 status
= LTTNG_ROTATION_STATUS_INVALID
;
95 status
= ask_rotation_info(rotation_handle
, &info
);
96 if (status
!= LTTNG_ROTATION_STATUS_OK
) {
100 *state
= (enum lttng_rotation_state
) info
->status
;
101 if (rotation_handle
->archive_location
||
102 *state
!= LTTNG_ROTATION_STATE_COMPLETED
) {
104 * The path is only provided by the sessiond once
105 * the session rotation is completed, but not expired.
111 * Cache the location since the rotation may expire before the user
112 * has a chance to query it.
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
;
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
)
129 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
130 struct lttng_rotation_get_info_return
*info
= NULL
;
132 if (!rotation_handle
|| !location
) {
133 status
= LTTNG_ROTATION_STATUS_INVALID
;
137 /* Use the cached location we got from a previous query. */
138 if (rotation_handle
->archive_location
) {
139 *location
= rotation_handle
->archive_location
;
143 status
= ask_rotation_info(rotation_handle
, &info
);
144 if (status
!= LTTNG_ROTATION_STATUS_OK
) {
148 if ((enum lttng_rotation_state
) info
->status
!=
149 LTTNG_ROTATION_STATE_COMPLETED
) {
150 status
= LTTNG_ROTATION_STATUS_UNAVAILABLE
;
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
;
165 void lttng_rotation_handle_destroy(
166 struct lttng_rotation_handle
*rotation_handle
)
168 if (!rotation_handle
) {
171 lttng_trace_archive_location_put(rotation_handle
->archive_location
);
172 free(rotation_handle
);
176 int init_rotation_handle(struct lttng_rotation_handle
*rotation_handle
,
177 const char *session_name
,
178 struct lttng_rotate_session_return
*rotate_return
)
182 ret
= lttng_strncpy(rotation_handle
->session_name
, session_name
,
183 sizeof(rotation_handle
->session_name
));
188 rotation_handle
->rotation_id
= rotate_return
->rotation_id
;
194 * Rotate the output folder of the session.
196 * Return 0 on success else a negative LTTng error code.
198 int lttng_rotate_session(const char *session_name
,
199 struct lttng_rotation_immediate_descriptor
*descriptor
,
200 struct lttng_rotation_handle
**rotation_handle
)
202 struct lttcomm_session_msg lsm
;
203 struct lttng_rotate_session_return
*rotate_return
= NULL
;
205 size_t session_name_len
;
208 ret
= -LTTNG_ERR_INVALID
;
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
;
219 memset(&lsm
, 0, sizeof(lsm
));
220 lsm
.cmd_type
= LTTNG_ROTATE_SESSION
;
222 ret
= lttng_strncpy(lsm
.session
.name
, session_name
,
223 sizeof(lsm
.session
.name
));
224 /* Source length already validated. */
225 LTTNG_ASSERT(ret
== 0);
227 ret
= lttng_ctl_ask_sessiond(&lsm
, (void **) &rotate_return
);
229 *rotation_handle
= NULL
;
233 *rotation_handle
= zmalloc(sizeof(struct lttng_rotation_handle
));
234 if (!*rotation_handle
) {
235 ret
= -LTTNG_ERR_NOMEM
;
239 init_rotation_handle(*rotation_handle
, session_name
, rotate_return
);
249 * Update the automatic rotation parameters.
250 * 'add' as true enables the provided schedule, false removes the shedule.
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).
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.
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.
266 enum lttng_rotation_status
lttng_rotation_update_schedule(
267 const char *session_name
,
268 const struct lttng_rotation_schedule
*schedule
,
271 struct lttcomm_session_msg lsm
;
272 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
275 if (!session_name
|| !schedule
) {
276 status
= LTTNG_ROTATION_STATUS_INVALID
;
280 if (strlen(session_name
) >= sizeof(lsm
.session
.name
)) {
281 status
= LTTNG_ROTATION_STATUS_INVALID
;
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);
292 lsm
.u
.rotation_set_schedule
.type
= (uint32_t) schedule
->type
;
293 switch (schedule
->type
) {
294 case LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD
:
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
;
306 lsm
.u
.rotation_set_schedule
.value
= threshold
;
307 lsm
.u
.rotation_set_schedule
.set
= !!add
;
310 case LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC
:
314 status
= lttng_rotation_schedule_periodic_get_period(
316 if (status
!= LTTNG_ROTATION_STATUS_OK
) {
317 if (status
== LTTNG_ROTATION_STATUS_UNAVAILABLE
) {
318 status
= LTTNG_ROTATION_STATUS_INVALID
;
322 lsm
.u
.rotation_set_schedule
.value
= period
;
323 lsm
.u
.rotation_set_schedule
.set
= !!add
;
327 status
= LTTNG_ROTATION_STATUS_INVALID
;
331 ret
= lttng_ctl_ask_sessiond(&lsm
, NULL
);
337 case LTTNG_ERR_ROTATION_SCHEDULE_SET
:
338 status
= LTTNG_ROTATION_STATUS_SCHEDULE_ALREADY_SET
;
340 case LTTNG_ERR_ROTATION_SCHEDULE_NOT_SET
:
341 status
= LTTNG_ROTATION_STATUS_INVALID
;
344 status
= LTTNG_ROTATION_STATUS_ERROR
;
351 struct lttng_rotation_schedules
*lttng_rotation_schedules_create(void)
353 return zmalloc(sizeof(struct lttng_rotation_schedules
));
357 void lttng_schedules_add(struct lttng_rotation_schedules
*schedules
,
358 struct lttng_rotation_schedule
*schedule
)
360 schedules
->schedules
[schedules
->count
++] = schedule
;
364 int get_schedules(const char *session_name
,
365 struct lttng_rotation_schedules
**_schedules
)
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
;
374 ret
= -LTTNG_ERR_INVALID
;
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
));
383 ret
= -LTTNG_ERR_INVALID
;
387 ret
= lttng_ctl_ask_sessiond(&lsm
, (void **) &schedules_comm
);
392 schedules
= lttng_rotation_schedules_create();
394 ret
= -LTTNG_ERR_NOMEM
;
398 if (schedules_comm
->periodic
.set
== 1) {
399 enum lttng_rotation_status status
;
401 periodic
= lttng_rotation_schedule_periodic_create();
403 ret
= -LTTNG_ERR_NOMEM
;
407 status
= lttng_rotation_schedule_periodic_set_period(
408 periodic
, schedules_comm
->periodic
.value
);
409 if (status
!= LTTNG_ROTATION_STATUS_OK
) {
411 * This would imply that the session daemon returned
412 * an invalid periodic rotation schedule value.
414 ret
= -LTTNG_ERR_UNK
;
418 lttng_schedules_add(schedules
, periodic
);
422 if (schedules_comm
->size
.set
== 1) {
423 enum lttng_rotation_status status
;
425 size
= lttng_rotation_schedule_size_threshold_create();
427 ret
= -LTTNG_ERR_NOMEM
;
431 status
= lttng_rotation_schedule_size_threshold_set_threshold(
432 size
, schedules_comm
->size
.value
);
433 if (status
!= LTTNG_ROTATION_STATUS_OK
) {
435 * This would imply that the session daemon returned
436 * an invalid size threshold schedule value.
438 ret
= -LTTNG_ERR_UNK
;
442 lttng_schedules_add(schedules
, size
);
448 free(schedules_comm
);
451 *_schedules
= schedules
;
455 enum lttng_rotation_schedule_type
lttng_rotation_schedule_get_type(
456 const struct lttng_rotation_schedule
*schedule
)
458 return schedule
? schedule
->type
: LTTNG_ROTATION_SCHEDULE_TYPE_UNKNOWN
;
461 struct lttng_rotation_schedule
*
462 lttng_rotation_schedule_size_threshold_create(void)
464 struct lttng_rotation_schedule_size_threshold
*schedule
;
466 schedule
= zmalloc(sizeof(*schedule
));
471 schedule
->parent
.type
= LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD
;
473 return &schedule
->parent
;
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
)
481 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
482 struct lttng_rotation_schedule_size_threshold
*size_schedule
;
484 if (!schedule
|| !size_threshold_bytes
||
485 schedule
->type
!= LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD
) {
486 status
= LTTNG_ROTATION_STATUS_INVALID
;
490 size_schedule
= container_of(schedule
,
491 struct lttng_rotation_schedule_size_threshold
,
493 if (size_schedule
->size
.set
) {
494 *size_threshold_bytes
= size_schedule
->size
.bytes
;
496 status
= LTTNG_ROTATION_STATUS_UNAVAILABLE
;
503 enum lttng_rotation_status
504 lttng_rotation_schedule_size_threshold_set_threshold(
505 struct lttng_rotation_schedule
*schedule
,
506 uint64_t size_threshold_bytes
)
508 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
509 struct lttng_rotation_schedule_size_threshold
*size_schedule
;
511 if (!schedule
|| size_threshold_bytes
== 0 ||
512 size_threshold_bytes
== -1ULL ||
513 schedule
->type
!= LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD
) {
514 status
= LTTNG_ROTATION_STATUS_INVALID
;
518 size_schedule
= container_of(schedule
,
519 struct lttng_rotation_schedule_size_threshold
,
521 size_schedule
->size
.bytes
= size_threshold_bytes
;
522 size_schedule
->size
.set
= true;
527 struct lttng_rotation_schedule
*
528 lttng_rotation_schedule_periodic_create(void)
530 struct lttng_rotation_schedule_periodic
*schedule
;
532 schedule
= zmalloc(sizeof(*schedule
));
537 schedule
->parent
.type
= LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC
;
539 return &schedule
->parent
;
542 enum lttng_rotation_status
543 lttng_rotation_schedule_periodic_get_period(
544 const struct lttng_rotation_schedule
*schedule
,
547 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
548 struct lttng_rotation_schedule_periodic
*periodic_schedule
;
550 if (!schedule
|| !period_us
||
551 schedule
->type
!= LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC
) {
552 status
= LTTNG_ROTATION_STATUS_INVALID
;
556 periodic_schedule
= container_of(schedule
,
557 struct lttng_rotation_schedule_periodic
,
559 if (periodic_schedule
->period
.set
) {
560 *period_us
= periodic_schedule
->period
.us
;
562 status
= LTTNG_ROTATION_STATUS_UNAVAILABLE
;
569 enum lttng_rotation_status
570 lttng_rotation_schedule_periodic_set_period(
571 struct lttng_rotation_schedule
*schedule
,
574 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
575 struct lttng_rotation_schedule_periodic
*periodic_schedule
;
577 if (!schedule
|| period_us
== 0 || period_us
== -1ULL ||
578 schedule
->type
!= LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC
) {
579 status
= LTTNG_ROTATION_STATUS_INVALID
;
583 periodic_schedule
= container_of(schedule
,
584 struct lttng_rotation_schedule_periodic
,
586 periodic_schedule
->period
.us
= period_us
;
587 periodic_schedule
->period
.set
= true;
592 void lttng_rotation_schedule_destroy(struct lttng_rotation_schedule
*schedule
)
600 void lttng_rotation_schedules_destroy(
601 struct lttng_rotation_schedules
*schedules
)
609 for (i
= 0; i
< schedules
->count
; i
++) {
610 lttng_rotation_schedule_destroy(schedules
->schedules
[i
]);
616 enum lttng_rotation_status
lttng_rotation_schedules_get_count(
617 const struct lttng_rotation_schedules
*schedules
,
620 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
622 if (!schedules
|| !count
) {
623 status
= LTTNG_ROTATION_STATUS_INVALID
;
627 *count
= schedules
->count
;
632 const struct lttng_rotation_schedule
*lttng_rotation_schedules_get_at_index(
633 const struct lttng_rotation_schedules
*schedules
,
636 const struct lttng_rotation_schedule
*schedule
= NULL
;
638 if (!schedules
|| index
>= schedules
->count
) {
642 schedule
= schedules
->schedules
[index
];
647 enum lttng_rotation_status
lttng_session_add_rotation_schedule(
648 const char *session_name
,
649 const struct lttng_rotation_schedule
*schedule
)
651 return lttng_rotation_update_schedule(session_name
, schedule
, true);
654 enum lttng_rotation_status
lttng_session_remove_rotation_schedule(
655 const char *session_name
,
656 const struct lttng_rotation_schedule
*schedule
)
658 return lttng_rotation_update_schedule(session_name
, schedule
, false);
661 int lttng_session_list_rotation_schedules(
662 const char *session_name
,
663 struct lttng_rotation_schedules
**schedules
)
665 return get_schedules(session_name
, schedules
);