2 * Copyright (C) 2017 Julien Desfossez <jdesfossez@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
12 #include <lttng/lttng-error.h>
13 #include <lttng/rotation.h>
14 #include <lttng/location-internal.h>
15 #include <lttng/rotate-internal.h>
16 #include <common/sessiond-comm/sessiond-comm.h>
17 #include <common/macros.h>
19 #include "lttng-ctl-helper.h"
22 enum lttng_rotation_status
ask_rotation_info(
23 struct lttng_rotation_handle
*rotation_handle
,
24 struct lttng_rotation_get_info_return
**info
)
26 /* lsm.get_rotation_state.rotation_id */
27 struct lttcomm_session_msg lsm
;
28 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
31 if (!rotation_handle
|| !info
) {
32 status
= LTTNG_ROTATION_STATUS_INVALID
;
36 memset(&lsm
, 0, sizeof(lsm
));
37 lsm
.cmd_type
= LTTNG_ROTATION_GET_INFO
;
38 lsm
.u
.get_rotation_info
.rotation_id
= rotation_handle
->rotation_id
;
40 ret
= lttng_strncpy(lsm
.session
.name
, rotation_handle
->session_name
,
41 sizeof(lsm
.session
.name
));
43 status
= LTTNG_ROTATION_STATUS_INVALID
;
47 ret
= lttng_ctl_ask_sessiond(&lsm
, (void **) info
);
49 status
= LTTNG_ROTATION_STATUS_ERROR
;
58 struct lttng_trace_archive_location
*
59 create_trace_archive_location_from_get_info(
60 const struct lttng_rotation_get_info_return
*info
)
62 struct lttng_trace_archive_location
*location
;
64 switch (info
->location_type
) {
65 case LTTNG_TRACE_ARCHIVE_LOCATION_TYPE_LOCAL
:
66 location
= lttng_trace_archive_location_local_create(
67 info
->location
.local
.absolute_path
);
69 case LTTNG_TRACE_ARCHIVE_LOCATION_TYPE_RELAY
:
70 location
= lttng_trace_archive_location_relay_create(
71 info
->location
.relay
.host
,
72 info
->location
.relay
.protocol
,
73 info
->location
.relay
.ports
.control
,
74 info
->location
.relay
.ports
.data
,
75 info
->location
.relay
.relative_path
);
84 enum lttng_rotation_status
lttng_rotation_handle_get_state(
85 struct lttng_rotation_handle
*rotation_handle
,
86 enum lttng_rotation_state
*state
)
88 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
89 struct lttng_rotation_get_info_return
*info
= NULL
;
91 if (!rotation_handle
|| !state
) {
92 status
= LTTNG_ROTATION_STATUS_INVALID
;
96 status
= ask_rotation_info(rotation_handle
, &info
);
97 if (status
!= LTTNG_ROTATION_STATUS_OK
) {
101 *state
= (enum lttng_rotation_state
) info
->status
;
102 if (rotation_handle
->archive_location
||
103 *state
!= LTTNG_ROTATION_STATE_COMPLETED
) {
105 * The path is only provided by the sessiond once
106 * the session rotation is completed, but not expired.
112 * Cache the location since the rotation may expire before the user
113 * has a chance to query it.
115 rotation_handle
->archive_location
=
116 create_trace_archive_location_from_get_info(info
);
117 if (!rotation_handle
->archive_location
) {
118 status
= LTTNG_ROTATION_STATUS_ERROR
;
126 enum lttng_rotation_status
lttng_rotation_handle_get_archive_location(
127 struct lttng_rotation_handle
*rotation_handle
,
128 const struct lttng_trace_archive_location
**location
)
130 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
131 struct lttng_rotation_get_info_return
*info
= NULL
;
133 if (!rotation_handle
|| !location
) {
134 status
= LTTNG_ROTATION_STATUS_INVALID
;
138 /* Use the cached location we got from a previous query. */
139 if (rotation_handle
->archive_location
) {
140 *location
= rotation_handle
->archive_location
;
144 status
= ask_rotation_info(rotation_handle
, &info
);
145 if (status
!= LTTNG_ROTATION_STATUS_OK
) {
149 if ((enum lttng_rotation_state
) info
->status
!=
150 LTTNG_ROTATION_STATE_COMPLETED
) {
151 status
= LTTNG_ROTATION_STATUS_UNAVAILABLE
;
155 rotation_handle
->archive_location
=
156 create_trace_archive_location_from_get_info(info
);
157 if (!rotation_handle
->archive_location
) {
158 status
= LTTNG_ROTATION_STATUS_ERROR
;
166 void lttng_rotation_handle_destroy(
167 struct lttng_rotation_handle
*rotation_handle
)
169 if (!rotation_handle
) {
172 lttng_trace_archive_location_destroy(rotation_handle
->archive_location
);
173 free(rotation_handle
);
177 int init_rotation_handle(struct lttng_rotation_handle
*rotation_handle
,
178 const char *session_name
,
179 struct lttng_rotate_session_return
*rotate_return
)
183 ret
= lttng_strncpy(rotation_handle
->session_name
, session_name
,
184 sizeof(rotation_handle
->session_name
));
189 rotation_handle
->rotation_id
= rotate_return
->rotation_id
;
195 * Rotate the output folder of the session.
197 * Return 0 on success else a negative LTTng error code.
199 int lttng_rotate_session(const char *session_name
,
200 struct lttng_rotation_immediate_descriptor
*descriptor
,
201 struct lttng_rotation_handle
**rotation_handle
)
203 struct lttcomm_session_msg lsm
;
204 struct lttng_rotate_session_return
*rotate_return
= NULL
;
206 size_t session_name_len
;
209 ret
= -LTTNG_ERR_INVALID
;
213 session_name_len
= strlen(session_name
);
214 if (session_name_len
>= sizeof(lsm
.session
.name
) ||
215 session_name_len
>= member_sizeof(struct lttng_rotation_handle
, session_name
)) {
216 ret
= -LTTNG_ERR_INVALID
;
220 memset(&lsm
, 0, sizeof(lsm
));
221 lsm
.cmd_type
= LTTNG_ROTATE_SESSION
;
222 lttng_ctl_copy_string(lsm
.session
.name
, session_name
,
223 sizeof(lsm
.session
.name
));
225 ret
= lttng_ctl_ask_sessiond(&lsm
, (void **) &rotate_return
);
227 *rotation_handle
= NULL
;
231 *rotation_handle
= zmalloc(sizeof(struct lttng_rotation_handle
));
232 if (!*rotation_handle
) {
233 ret
= -LTTNG_ERR_NOMEM
;
237 init_rotation_handle(*rotation_handle
, session_name
, rotate_return
);
247 * Update the automatic rotation parameters.
248 * 'add' as true enables the provided schedule, false removes the shedule.
250 * The external API makes it appear as though arbitrary schedules can
251 * be added or removed at will. However, the session daemon is
252 * currently limited to one schedule per type (per session).
254 * The additional flexibility of the public API is offered for future
255 * rotation schedules that could indicate more precise criteria than
256 * size and time (e.g. a domain) where it could make sense to add
257 * multiple schedules of a given type to a session.
259 * Hence, the exact schedule that the user wishes to remove (and not
260 * just its type) must be passed so that the session daemon can
261 * validate that is exists before clearing it.
264 enum lttng_rotation_status
lttng_rotation_update_schedule(
265 const char *session_name
,
266 const struct lttng_rotation_schedule
*schedule
,
269 struct lttcomm_session_msg lsm
;
270 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
273 if (!session_name
|| !schedule
) {
274 status
= LTTNG_ROTATION_STATUS_INVALID
;
278 if (strlen(session_name
) >= sizeof(lsm
.session
.name
)) {
279 status
= LTTNG_ROTATION_STATUS_INVALID
;
283 memset(&lsm
, 0, sizeof(lsm
));
284 lsm
.cmd_type
= LTTNG_ROTATION_SET_SCHEDULE
;
285 lttng_ctl_copy_string(lsm
.session
.name
, session_name
,
286 sizeof(lsm
.session
.name
));
288 lsm
.u
.rotation_set_schedule
.type
= (uint32_t) schedule
->type
;
289 switch (schedule
->type
) {
290 case LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD
:
294 status
= lttng_rotation_schedule_size_threshold_get_threshold(
295 schedule
, &threshold
);
296 if (status
!= LTTNG_ROTATION_STATUS_OK
) {
297 if (status
== LTTNG_ROTATION_STATUS_UNAVAILABLE
) {
298 status
= LTTNG_ROTATION_STATUS_INVALID
;
302 lsm
.u
.rotation_set_schedule
.value
= threshold
;
303 lsm
.u
.rotation_set_schedule
.set
= !!add
;
306 case LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC
:
310 status
= lttng_rotation_schedule_periodic_get_period(
312 if (status
!= LTTNG_ROTATION_STATUS_OK
) {
313 if (status
== LTTNG_ROTATION_STATUS_UNAVAILABLE
) {
314 status
= LTTNG_ROTATION_STATUS_INVALID
;
318 lsm
.u
.rotation_set_schedule
.value
= period
;
319 lsm
.u
.rotation_set_schedule
.set
= !!add
;
323 status
= LTTNG_ROTATION_STATUS_INVALID
;
327 ret
= lttng_ctl_ask_sessiond(&lsm
, NULL
);
333 case LTTNG_ERR_ROTATION_SCHEDULE_SET
:
334 status
= LTTNG_ROTATION_STATUS_SCHEDULE_ALREADY_SET
;
336 case LTTNG_ERR_ROTATION_SCHEDULE_NOT_SET
:
337 status
= LTTNG_ROTATION_STATUS_INVALID
;
340 status
= LTTNG_ROTATION_STATUS_ERROR
;
347 struct lttng_rotation_schedules
*lttng_rotation_schedules_create(void)
349 return zmalloc(sizeof(struct lttng_rotation_schedules
));
353 void lttng_schedules_add(struct lttng_rotation_schedules
*schedules
,
354 struct lttng_rotation_schedule
*schedule
)
356 schedules
->schedules
[schedules
->count
++] = schedule
;
360 int get_schedules(const char *session_name
,
361 struct lttng_rotation_schedules
**_schedules
)
364 struct lttcomm_session_msg lsm
;
365 struct lttng_session_list_schedules_return
*schedules_comm
= NULL
;
366 struct lttng_rotation_schedules
*schedules
= NULL
;
367 struct lttng_rotation_schedule
*periodic
= NULL
, *size
= NULL
;
369 memset(&lsm
, 0, sizeof(lsm
));
370 lsm
.cmd_type
= LTTNG_SESSION_LIST_ROTATION_SCHEDULES
;
371 lttng_ctl_copy_string(lsm
.session
.name
, session_name
,
372 sizeof(lsm
.session
.name
));
374 ret
= lttng_ctl_ask_sessiond(&lsm
, (void **) &schedules_comm
);
379 schedules
= lttng_rotation_schedules_create();
381 ret
= -LTTNG_ERR_NOMEM
;
385 if (schedules_comm
->periodic
.set
== 1) {
386 enum lttng_rotation_status status
;
388 periodic
= lttng_rotation_schedule_periodic_create();
390 ret
= -LTTNG_ERR_NOMEM
;
394 status
= lttng_rotation_schedule_periodic_set_period(
395 periodic
, schedules_comm
->periodic
.value
);
396 if (status
!= LTTNG_ROTATION_STATUS_OK
) {
398 * This would imply that the session daemon returned
399 * an invalid periodic rotation schedule value.
401 ret
= -LTTNG_ERR_UNK
;
405 lttng_schedules_add(schedules
, periodic
);
409 if (schedules_comm
->size
.set
== 1) {
410 enum lttng_rotation_status status
;
412 size
= lttng_rotation_schedule_size_threshold_create();
414 ret
= -LTTNG_ERR_NOMEM
;
418 status
= lttng_rotation_schedule_size_threshold_set_threshold(
419 size
, schedules_comm
->size
.value
);
420 if (status
!= LTTNG_ROTATION_STATUS_OK
) {
422 * This would imply that the session daemon returned
423 * an invalid size threshold schedule value.
425 ret
= -LTTNG_ERR_UNK
;
429 lttng_schedules_add(schedules
, size
);
435 free(schedules_comm
);
438 *_schedules
= schedules
;
442 enum lttng_rotation_schedule_type
lttng_rotation_schedule_get_type(
443 const struct lttng_rotation_schedule
*schedule
)
445 return schedule
? schedule
->type
: LTTNG_ROTATION_SCHEDULE_TYPE_UNKNOWN
;
448 struct lttng_rotation_schedule
*
449 lttng_rotation_schedule_size_threshold_create(void)
451 struct lttng_rotation_schedule_size_threshold
*schedule
;
453 schedule
= zmalloc(sizeof(*schedule
));
458 schedule
->parent
.type
= LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD
;
460 return &schedule
->parent
;
463 enum lttng_rotation_status
464 lttng_rotation_schedule_size_threshold_get_threshold(
465 const struct lttng_rotation_schedule
*schedule
,
466 uint64_t *size_threshold_bytes
)
468 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
469 struct lttng_rotation_schedule_size_threshold
*size_schedule
;
471 if (!schedule
|| !size_threshold_bytes
||
472 schedule
->type
!= LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD
) {
473 status
= LTTNG_ROTATION_STATUS_INVALID
;
477 size_schedule
= container_of(schedule
,
478 struct lttng_rotation_schedule_size_threshold
,
480 if (size_schedule
->size
.set
) {
481 *size_threshold_bytes
= size_schedule
->size
.bytes
;
483 status
= LTTNG_ROTATION_STATUS_UNAVAILABLE
;
490 enum lttng_rotation_status
491 lttng_rotation_schedule_size_threshold_set_threshold(
492 struct lttng_rotation_schedule
*schedule
,
493 uint64_t size_threshold_bytes
)
495 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
496 struct lttng_rotation_schedule_size_threshold
*size_schedule
;
498 if (!schedule
|| size_threshold_bytes
== 0 ||
499 size_threshold_bytes
== -1ULL ||
500 schedule
->type
!= LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD
) {
501 status
= LTTNG_ROTATION_STATUS_INVALID
;
505 size_schedule
= container_of(schedule
,
506 struct lttng_rotation_schedule_size_threshold
,
508 size_schedule
->size
.bytes
= size_threshold_bytes
;
509 size_schedule
->size
.set
= true;
514 struct lttng_rotation_schedule
*
515 lttng_rotation_schedule_periodic_create(void)
517 struct lttng_rotation_schedule_periodic
*schedule
;
519 schedule
= zmalloc(sizeof(*schedule
));
524 schedule
->parent
.type
= LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC
;
526 return &schedule
->parent
;
529 enum lttng_rotation_status
530 lttng_rotation_schedule_periodic_get_period(
531 const struct lttng_rotation_schedule
*schedule
,
534 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
535 struct lttng_rotation_schedule_periodic
*periodic_schedule
;
537 if (!schedule
|| !period_us
||
538 schedule
->type
!= LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC
) {
539 status
= LTTNG_ROTATION_STATUS_INVALID
;
543 periodic_schedule
= container_of(schedule
,
544 struct lttng_rotation_schedule_periodic
,
546 if (periodic_schedule
->period
.set
) {
547 *period_us
= periodic_schedule
->period
.us
;
549 status
= LTTNG_ROTATION_STATUS_UNAVAILABLE
;
556 enum lttng_rotation_status
557 lttng_rotation_schedule_periodic_set_period(
558 struct lttng_rotation_schedule
*schedule
,
561 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
562 struct lttng_rotation_schedule_periodic
*periodic_schedule
;
564 if (!schedule
|| period_us
== 0 || period_us
== -1ULL ||
565 schedule
->type
!= LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC
) {
566 status
= LTTNG_ROTATION_STATUS_INVALID
;
570 periodic_schedule
= container_of(schedule
,
571 struct lttng_rotation_schedule_periodic
,
573 periodic_schedule
->period
.us
= period_us
;
574 periodic_schedule
->period
.set
= true;
579 void lttng_rotation_schedule_destroy(struct lttng_rotation_schedule
*schedule
)
587 void lttng_rotation_schedules_destroy(
588 struct lttng_rotation_schedules
*schedules
)
596 for (i
= 0; i
< schedules
->count
; i
++) {
597 lttng_rotation_schedule_destroy(schedules
->schedules
[i
]);
603 enum lttng_rotation_status
lttng_rotation_schedules_get_count(
604 const struct lttng_rotation_schedules
*schedules
,
607 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
609 if (!schedules
|| !count
) {
610 status
= LTTNG_ROTATION_STATUS_INVALID
;
614 *count
= schedules
->count
;
619 const struct lttng_rotation_schedule
*lttng_rotation_schedules_get_at_index(
620 const struct lttng_rotation_schedules
*schedules
,
623 const struct lttng_rotation_schedule
*schedule
= NULL
;
625 if (!schedules
|| index
>= schedules
->count
) {
629 schedule
= schedules
->schedules
[index
];
634 enum lttng_rotation_status
lttng_session_add_rotation_schedule(
635 const char *session_name
,
636 const struct lttng_rotation_schedule
*schedule
)
638 return lttng_rotation_update_schedule(session_name
, schedule
, true);
641 enum lttng_rotation_status
lttng_session_remove_rotation_schedule(
642 const char *session_name
,
643 const struct lttng_rotation_schedule
*schedule
)
645 return lttng_rotation_update_schedule(session_name
, schedule
, false);
648 int lttng_session_list_rotation_schedules(
649 const char *session_name
,
650 struct lttng_rotation_schedules
**schedules
)
652 return get_schedules(session_name
, schedules
);