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
;
223 ret
= lttng_strncpy(lsm
.session
.name
, session_name
,
224 sizeof(lsm
.session
.name
));
225 /* Source length already validated. */
228 ret
= lttng_ctl_ask_sessiond(&lsm
, (void **) &rotate_return
);
230 *rotation_handle
= NULL
;
234 *rotation_handle
= zmalloc(sizeof(struct lttng_rotation_handle
));
235 if (!*rotation_handle
) {
236 ret
= -LTTNG_ERR_NOMEM
;
240 init_rotation_handle(*rotation_handle
, session_name
, rotate_return
);
250 * Update the automatic rotation parameters.
251 * 'add' as true enables the provided schedule, false removes the shedule.
253 * The external API makes it appear as though arbitrary schedules can
254 * be added or removed at will. However, the session daemon is
255 * currently limited to one schedule per type (per session).
257 * The additional flexibility of the public API is offered for future
258 * rotation schedules that could indicate more precise criteria than
259 * size and time (e.g. a domain) where it could make sense to add
260 * multiple schedules of a given type to a session.
262 * Hence, the exact schedule that the user wishes to remove (and not
263 * just its type) must be passed so that the session daemon can
264 * validate that is exists before clearing it.
267 enum lttng_rotation_status
lttng_rotation_update_schedule(
268 const char *session_name
,
269 const struct lttng_rotation_schedule
*schedule
,
272 struct lttcomm_session_msg lsm
;
273 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
276 if (!session_name
|| !schedule
) {
277 status
= LTTNG_ROTATION_STATUS_INVALID
;
281 if (strlen(session_name
) >= sizeof(lsm
.session
.name
)) {
282 status
= LTTNG_ROTATION_STATUS_INVALID
;
286 memset(&lsm
, 0, sizeof(lsm
));
287 lsm
.cmd_type
= LTTNG_ROTATION_SET_SCHEDULE
;
288 ret
= lttng_strncpy(lsm
.session
.name
, session_name
,
289 sizeof(lsm
.session
.name
));
290 /* Source length already validated. */
293 lsm
.u
.rotation_set_schedule
.type
= (uint32_t) schedule
->type
;
294 switch (schedule
->type
) {
295 case LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD
:
299 status
= lttng_rotation_schedule_size_threshold_get_threshold(
300 schedule
, &threshold
);
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
= threshold
;
308 lsm
.u
.rotation_set_schedule
.set
= !!add
;
311 case LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC
:
315 status
= lttng_rotation_schedule_periodic_get_period(
317 if (status
!= LTTNG_ROTATION_STATUS_OK
) {
318 if (status
== LTTNG_ROTATION_STATUS_UNAVAILABLE
) {
319 status
= LTTNG_ROTATION_STATUS_INVALID
;
323 lsm
.u
.rotation_set_schedule
.value
= period
;
324 lsm
.u
.rotation_set_schedule
.set
= !!add
;
328 status
= LTTNG_ROTATION_STATUS_INVALID
;
332 ret
= lttng_ctl_ask_sessiond(&lsm
, NULL
);
338 case LTTNG_ERR_ROTATION_SCHEDULE_SET
:
339 status
= LTTNG_ROTATION_STATUS_SCHEDULE_ALREADY_SET
;
341 case LTTNG_ERR_ROTATION_SCHEDULE_NOT_SET
:
342 status
= LTTNG_ROTATION_STATUS_INVALID
;
345 status
= LTTNG_ROTATION_STATUS_ERROR
;
352 struct lttng_rotation_schedules
*lttng_rotation_schedules_create(void)
354 return zmalloc(sizeof(struct lttng_rotation_schedules
));
358 void lttng_schedules_add(struct lttng_rotation_schedules
*schedules
,
359 struct lttng_rotation_schedule
*schedule
)
361 schedules
->schedules
[schedules
->count
++] = schedule
;
365 int get_schedules(const char *session_name
,
366 struct lttng_rotation_schedules
**_schedules
)
369 struct lttcomm_session_msg lsm
;
370 struct lttng_session_list_schedules_return
*schedules_comm
= NULL
;
371 struct lttng_rotation_schedules
*schedules
= NULL
;
372 struct lttng_rotation_schedule
*periodic
= NULL
, *size
= NULL
;
375 ret
= -LTTNG_ERR_INVALID
;
379 memset(&lsm
, 0, sizeof(lsm
));
380 lsm
.cmd_type
= LTTNG_SESSION_LIST_ROTATION_SCHEDULES
;
381 ret
= lttng_strncpy(lsm
.session
.name
, session_name
,
382 sizeof(lsm
.session
.name
));
384 ret
= -LTTNG_ERR_INVALID
;
388 ret
= lttng_ctl_ask_sessiond(&lsm
, (void **) &schedules_comm
);
393 schedules
= lttng_rotation_schedules_create();
395 ret
= -LTTNG_ERR_NOMEM
;
399 if (schedules_comm
->periodic
.set
== 1) {
400 enum lttng_rotation_status status
;
402 periodic
= lttng_rotation_schedule_periodic_create();
404 ret
= -LTTNG_ERR_NOMEM
;
408 status
= lttng_rotation_schedule_periodic_set_period(
409 periodic
, schedules_comm
->periodic
.value
);
410 if (status
!= LTTNG_ROTATION_STATUS_OK
) {
412 * This would imply that the session daemon returned
413 * an invalid periodic rotation schedule value.
415 ret
= -LTTNG_ERR_UNK
;
419 lttng_schedules_add(schedules
, periodic
);
423 if (schedules_comm
->size
.set
== 1) {
424 enum lttng_rotation_status status
;
426 size
= lttng_rotation_schedule_size_threshold_create();
428 ret
= -LTTNG_ERR_NOMEM
;
432 status
= lttng_rotation_schedule_size_threshold_set_threshold(
433 size
, schedules_comm
->size
.value
);
434 if (status
!= LTTNG_ROTATION_STATUS_OK
) {
436 * This would imply that the session daemon returned
437 * an invalid size threshold schedule value.
439 ret
= -LTTNG_ERR_UNK
;
443 lttng_schedules_add(schedules
, size
);
449 free(schedules_comm
);
452 *_schedules
= schedules
;
456 enum lttng_rotation_schedule_type
lttng_rotation_schedule_get_type(
457 const struct lttng_rotation_schedule
*schedule
)
459 return schedule
? schedule
->type
: LTTNG_ROTATION_SCHEDULE_TYPE_UNKNOWN
;
462 struct lttng_rotation_schedule
*
463 lttng_rotation_schedule_size_threshold_create(void)
465 struct lttng_rotation_schedule_size_threshold
*schedule
;
467 schedule
= zmalloc(sizeof(*schedule
));
472 schedule
->parent
.type
= LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD
;
474 return &schedule
->parent
;
477 enum lttng_rotation_status
478 lttng_rotation_schedule_size_threshold_get_threshold(
479 const struct lttng_rotation_schedule
*schedule
,
480 uint64_t *size_threshold_bytes
)
482 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
483 struct lttng_rotation_schedule_size_threshold
*size_schedule
;
485 if (!schedule
|| !size_threshold_bytes
||
486 schedule
->type
!= LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD
) {
487 status
= LTTNG_ROTATION_STATUS_INVALID
;
491 size_schedule
= container_of(schedule
,
492 struct lttng_rotation_schedule_size_threshold
,
494 if (size_schedule
->size
.set
) {
495 *size_threshold_bytes
= size_schedule
->size
.bytes
;
497 status
= LTTNG_ROTATION_STATUS_UNAVAILABLE
;
504 enum lttng_rotation_status
505 lttng_rotation_schedule_size_threshold_set_threshold(
506 struct lttng_rotation_schedule
*schedule
,
507 uint64_t size_threshold_bytes
)
509 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
510 struct lttng_rotation_schedule_size_threshold
*size_schedule
;
512 if (!schedule
|| size_threshold_bytes
== 0 ||
513 size_threshold_bytes
== -1ULL ||
514 schedule
->type
!= LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD
) {
515 status
= LTTNG_ROTATION_STATUS_INVALID
;
519 size_schedule
= container_of(schedule
,
520 struct lttng_rotation_schedule_size_threshold
,
522 size_schedule
->size
.bytes
= size_threshold_bytes
;
523 size_schedule
->size
.set
= true;
528 struct lttng_rotation_schedule
*
529 lttng_rotation_schedule_periodic_create(void)
531 struct lttng_rotation_schedule_periodic
*schedule
;
533 schedule
= zmalloc(sizeof(*schedule
));
538 schedule
->parent
.type
= LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC
;
540 return &schedule
->parent
;
543 enum lttng_rotation_status
544 lttng_rotation_schedule_periodic_get_period(
545 const struct lttng_rotation_schedule
*schedule
,
548 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
549 struct lttng_rotation_schedule_periodic
*periodic_schedule
;
551 if (!schedule
|| !period_us
||
552 schedule
->type
!= LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC
) {
553 status
= LTTNG_ROTATION_STATUS_INVALID
;
557 periodic_schedule
= container_of(schedule
,
558 struct lttng_rotation_schedule_periodic
,
560 if (periodic_schedule
->period
.set
) {
561 *period_us
= periodic_schedule
->period
.us
;
563 status
= LTTNG_ROTATION_STATUS_UNAVAILABLE
;
570 enum lttng_rotation_status
571 lttng_rotation_schedule_periodic_set_period(
572 struct lttng_rotation_schedule
*schedule
,
575 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
576 struct lttng_rotation_schedule_periodic
*periodic_schedule
;
578 if (!schedule
|| period_us
== 0 || period_us
== -1ULL ||
579 schedule
->type
!= LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC
) {
580 status
= LTTNG_ROTATION_STATUS_INVALID
;
584 periodic_schedule
= container_of(schedule
,
585 struct lttng_rotation_schedule_periodic
,
587 periodic_schedule
->period
.us
= period_us
;
588 periodic_schedule
->period
.set
= true;
593 void lttng_rotation_schedule_destroy(struct lttng_rotation_schedule
*schedule
)
601 void lttng_rotation_schedules_destroy(
602 struct lttng_rotation_schedules
*schedules
)
610 for (i
= 0; i
< schedules
->count
; i
++) {
611 lttng_rotation_schedule_destroy(schedules
->schedules
[i
]);
617 enum lttng_rotation_status
lttng_rotation_schedules_get_count(
618 const struct lttng_rotation_schedules
*schedules
,
621 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
623 if (!schedules
|| !count
) {
624 status
= LTTNG_ROTATION_STATUS_INVALID
;
628 *count
= schedules
->count
;
633 const struct lttng_rotation_schedule
*lttng_rotation_schedules_get_at_index(
634 const struct lttng_rotation_schedules
*schedules
,
637 const struct lttng_rotation_schedule
*schedule
= NULL
;
639 if (!schedules
|| index
>= schedules
->count
) {
643 schedule
= schedules
->schedules
[index
];
648 enum lttng_rotation_status
lttng_session_add_rotation_schedule(
649 const char *session_name
,
650 const struct lttng_rotation_schedule
*schedule
)
652 return lttng_rotation_update_schedule(session_name
, schedule
, true);
655 enum lttng_rotation_status
lttng_session_remove_rotation_schedule(
656 const char *session_name
,
657 const struct lttng_rotation_schedule
*schedule
)
659 return lttng_rotation_update_schedule(session_name
, schedule
, false);
662 int lttng_session_list_rotation_schedules(
663 const char *session_name
,
664 struct lttng_rotation_schedules
**schedules
)
666 return get_schedules(session_name
, schedules
);