2 * Copyright (C) 2017 - Julien Desfossez <jdesfossez@efficios.com>
4 * This library is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License, version 2.1 only,
6 * as published by the Free Software Foundation.
8 * This library is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, write to the Free Software Foundation,
15 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include <lttng/lttng-error.h>
23 #include <lttng/rotation.h>
24 #include <lttng/location-internal.h>
25 #include <lttng/rotate-internal.h>
26 #include <common/sessiond-comm/sessiond-comm.h>
27 #include <common/macros.h>
29 #include "lttng-ctl-helper.h"
32 enum lttng_rotation_status
ask_rotation_info(
33 struct lttng_rotation_handle
*rotation_handle
,
34 struct lttng_rotation_get_info_return
**info
)
36 /* lsm.get_rotation_state.rotation_id */
37 struct lttcomm_session_msg lsm
;
38 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
41 if (!rotation_handle
|| !info
) {
42 status
= LTTNG_ROTATION_STATUS_INVALID
;
46 memset(&lsm
, 0, sizeof(lsm
));
47 lsm
.cmd_type
= LTTNG_ROTATION_GET_INFO
;
48 lsm
.u
.get_rotation_info
.rotation_id
= rotation_handle
->rotation_id
;
50 ret
= lttng_strncpy(lsm
.session
.name
, rotation_handle
->session_name
,
51 sizeof(lsm
.session
.name
));
53 status
= LTTNG_ROTATION_STATUS_INVALID
;
57 ret
= lttng_ctl_ask_sessiond(&lsm
, (void **) info
);
59 status
= LTTNG_ROTATION_STATUS_ERROR
;
68 struct lttng_trace_archive_location
*
69 create_trace_archive_location_from_get_info(
70 const struct lttng_rotation_get_info_return
*info
)
72 struct lttng_trace_archive_location
*location
;
74 switch (info
->location_type
) {
75 case LTTNG_TRACE_ARCHIVE_LOCATION_TYPE_LOCAL
:
76 location
= lttng_trace_archive_location_local_create(
77 info
->location
.local
.absolute_path
);
79 case LTTNG_TRACE_ARCHIVE_LOCATION_TYPE_RELAY
:
80 location
= lttng_trace_archive_location_relay_create(
81 info
->location
.relay
.host
,
82 info
->location
.relay
.protocol
,
83 info
->location
.relay
.ports
.control
,
84 info
->location
.relay
.ports
.data
,
85 info
->location
.relay
.relative_path
);
94 enum lttng_rotation_status
lttng_rotation_handle_get_state(
95 struct lttng_rotation_handle
*rotation_handle
,
96 enum lttng_rotation_state
*state
)
98 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
99 struct lttng_rotation_get_info_return
*info
= NULL
;
101 if (!rotation_handle
|| !state
) {
102 status
= LTTNG_ROTATION_STATUS_INVALID
;
106 status
= ask_rotation_info(rotation_handle
, &info
);
107 if (status
!= LTTNG_ROTATION_STATUS_OK
) {
111 *state
= (enum lttng_rotation_state
) info
->status
;
112 if (rotation_handle
->archive_location
||
113 *state
!= LTTNG_ROTATION_STATE_COMPLETED
) {
115 * The path is only provided by the sessiond once
116 * the session rotation is completed, but not expired.
122 * Cache the location since the rotation may expire before the user
123 * has a chance to query it.
125 rotation_handle
->archive_location
=
126 create_trace_archive_location_from_get_info(info
);
127 if (!rotation_handle
->archive_location
) {
128 status
= LTTNG_ROTATION_STATUS_ERROR
;
136 enum lttng_rotation_status
lttng_rotation_handle_get_archive_location(
137 struct lttng_rotation_handle
*rotation_handle
,
138 const struct lttng_trace_archive_location
**location
)
140 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
141 struct lttng_rotation_get_info_return
*info
= NULL
;
143 if (!rotation_handle
|| !location
) {
144 status
= LTTNG_ROTATION_STATUS_INVALID
;
148 /* Use the cached location we got from a previous query. */
149 if (rotation_handle
->archive_location
) {
150 *location
= rotation_handle
->archive_location
;
154 status
= ask_rotation_info(rotation_handle
, &info
);
155 if (status
!= LTTNG_ROTATION_STATUS_OK
) {
159 if ((enum lttng_rotation_state
) info
->status
!=
160 LTTNG_ROTATION_STATE_COMPLETED
) {
161 status
= LTTNG_ROTATION_STATUS_UNAVAILABLE
;
165 rotation_handle
->archive_location
=
166 create_trace_archive_location_from_get_info(info
);
167 if (!rotation_handle
->archive_location
) {
168 status
= LTTNG_ROTATION_STATUS_ERROR
;
176 void lttng_rotation_handle_destroy(
177 struct lttng_rotation_handle
*rotation_handle
)
179 if (!rotation_handle
) {
182 lttng_trace_archive_location_destroy(rotation_handle
->archive_location
);
183 free(rotation_handle
);
187 int init_rotation_handle(struct lttng_rotation_handle
*rotation_handle
,
188 const char *session_name
,
189 struct lttng_rotate_session_return
*rotate_return
)
193 ret
= lttng_strncpy(rotation_handle
->session_name
, session_name
,
194 sizeof(rotation_handle
->session_name
));
199 rotation_handle
->rotation_id
= rotate_return
->rotation_id
;
205 * Rotate the output folder of the session.
207 * Return 0 on success else a negative LTTng error code.
209 int lttng_rotate_session(const char *session_name
,
210 struct lttng_rotation_immediate_descriptor
*descriptor
,
211 struct lttng_rotation_handle
**rotation_handle
)
213 struct lttcomm_session_msg lsm
;
214 struct lttng_rotate_session_return
*rotate_return
= NULL
;
216 size_t session_name_len
;
219 ret
= -LTTNG_ERR_INVALID
;
223 session_name_len
= strlen(session_name
);
224 if (session_name_len
>= sizeof(lsm
.session
.name
) ||
225 session_name_len
>= member_sizeof(struct lttng_rotation_handle
, session_name
)) {
226 ret
= -LTTNG_ERR_INVALID
;
230 memset(&lsm
, 0, sizeof(lsm
));
231 lsm
.cmd_type
= LTTNG_ROTATE_SESSION
;
233 ret
= lttng_strncpy(lsm
.session
.name
, session_name
,
234 sizeof(lsm
.session
.name
));
235 /* Source length already validated. */
238 ret
= lttng_ctl_ask_sessiond(&lsm
, (void **) &rotate_return
);
240 *rotation_handle
= NULL
;
244 *rotation_handle
= zmalloc(sizeof(struct lttng_rotation_handle
));
245 if (!*rotation_handle
) {
246 ret
= -LTTNG_ERR_NOMEM
;
250 init_rotation_handle(*rotation_handle
, session_name
, rotate_return
);
260 * Update the automatic rotation parameters.
261 * 'add' as true enables the provided schedule, false removes the shedule.
263 * The external API makes it appear as though arbitrary schedules can
264 * be added or removed at will. However, the session daemon is
265 * currently limited to one schedule per type (per session).
267 * The additional flexibility of the public API is offered for future
268 * rotation schedules that could indicate more precise criteria than
269 * size and time (e.g. a domain) where it could make sense to add
270 * multiple schedules of a given type to a session.
272 * Hence, the exact schedule that the user wishes to remove (and not
273 * just its type) must be passed so that the session daemon can
274 * validate that is exists before clearing it.
277 enum lttng_rotation_status
lttng_rotation_update_schedule(
278 const char *session_name
,
279 const struct lttng_rotation_schedule
*schedule
,
282 struct lttcomm_session_msg lsm
;
283 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
286 if (!session_name
|| !schedule
) {
287 status
= LTTNG_ROTATION_STATUS_INVALID
;
291 if (strlen(session_name
) >= sizeof(lsm
.session
.name
)) {
292 status
= LTTNG_ROTATION_STATUS_INVALID
;
296 memset(&lsm
, 0, sizeof(lsm
));
297 lsm
.cmd_type
= LTTNG_ROTATION_SET_SCHEDULE
;
298 ret
= lttng_strncpy(lsm
.session
.name
, session_name
,
299 sizeof(lsm
.session
.name
));
300 /* Source length already validated. */
303 lsm
.u
.rotation_set_schedule
.type
= (uint32_t) schedule
->type
;
304 switch (schedule
->type
) {
305 case LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD
:
309 status
= lttng_rotation_schedule_size_threshold_get_threshold(
310 schedule
, &threshold
);
311 if (status
!= LTTNG_ROTATION_STATUS_OK
) {
312 if (status
== LTTNG_ROTATION_STATUS_UNAVAILABLE
) {
313 status
= LTTNG_ROTATION_STATUS_INVALID
;
317 lsm
.u
.rotation_set_schedule
.value
= threshold
;
318 lsm
.u
.rotation_set_schedule
.set
= !!add
;
321 case LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC
:
325 status
= lttng_rotation_schedule_periodic_get_period(
327 if (status
!= LTTNG_ROTATION_STATUS_OK
) {
328 if (status
== LTTNG_ROTATION_STATUS_UNAVAILABLE
) {
329 status
= LTTNG_ROTATION_STATUS_INVALID
;
333 lsm
.u
.rotation_set_schedule
.value
= period
;
334 lsm
.u
.rotation_set_schedule
.set
= !!add
;
338 status
= LTTNG_ROTATION_STATUS_INVALID
;
342 ret
= lttng_ctl_ask_sessiond(&lsm
, NULL
);
348 case LTTNG_ERR_ROTATION_SCHEDULE_SET
:
349 status
= LTTNG_ROTATION_STATUS_SCHEDULE_ALREADY_SET
;
351 case LTTNG_ERR_ROTATION_SCHEDULE_NOT_SET
:
352 status
= LTTNG_ROTATION_STATUS_INVALID
;
355 status
= LTTNG_ROTATION_STATUS_ERROR
;
362 struct lttng_rotation_schedules
*lttng_rotation_schedules_create(void)
364 return zmalloc(sizeof(struct lttng_rotation_schedules
));
368 void lttng_schedules_add(struct lttng_rotation_schedules
*schedules
,
369 struct lttng_rotation_schedule
*schedule
)
371 schedules
->schedules
[schedules
->count
++] = schedule
;
375 int get_schedules(const char *session_name
,
376 struct lttng_rotation_schedules
**_schedules
)
379 struct lttcomm_session_msg lsm
;
380 struct lttng_session_list_schedules_return
*schedules_comm
= NULL
;
381 struct lttng_rotation_schedules
*schedules
= NULL
;
382 struct lttng_rotation_schedule
*periodic
= NULL
, *size
= NULL
;
385 ret
= -LTTNG_ERR_INVALID
;
389 memset(&lsm
, 0, sizeof(lsm
));
390 lsm
.cmd_type
= LTTNG_SESSION_LIST_ROTATION_SCHEDULES
;
391 ret
= lttng_strncpy(lsm
.session
.name
, session_name
,
392 sizeof(lsm
.session
.name
));
394 ret
= -LTTNG_ERR_INVALID
;
398 ret
= lttng_ctl_ask_sessiond(&lsm
, (void **) &schedules_comm
);
403 schedules
= lttng_rotation_schedules_create();
405 ret
= -LTTNG_ERR_NOMEM
;
409 if (schedules_comm
->periodic
.set
== 1) {
410 enum lttng_rotation_status status
;
412 periodic
= lttng_rotation_schedule_periodic_create();
414 ret
= -LTTNG_ERR_NOMEM
;
418 status
= lttng_rotation_schedule_periodic_set_period(
419 periodic
, schedules_comm
->periodic
.value
);
420 if (status
!= LTTNG_ROTATION_STATUS_OK
) {
422 * This would imply that the session daemon returned
423 * an invalid periodic rotation schedule value.
425 ret
= -LTTNG_ERR_UNK
;
429 lttng_schedules_add(schedules
, periodic
);
433 if (schedules_comm
->size
.set
== 1) {
434 enum lttng_rotation_status status
;
436 size
= lttng_rotation_schedule_size_threshold_create();
438 ret
= -LTTNG_ERR_NOMEM
;
442 status
= lttng_rotation_schedule_size_threshold_set_threshold(
443 size
, schedules_comm
->size
.value
);
444 if (status
!= LTTNG_ROTATION_STATUS_OK
) {
446 * This would imply that the session daemon returned
447 * an invalid size threshold schedule value.
449 ret
= -LTTNG_ERR_UNK
;
453 lttng_schedules_add(schedules
, size
);
459 free(schedules_comm
);
462 *_schedules
= schedules
;
466 enum lttng_rotation_schedule_type
lttng_rotation_schedule_get_type(
467 const struct lttng_rotation_schedule
*schedule
)
469 return schedule
? schedule
->type
: LTTNG_ROTATION_SCHEDULE_TYPE_UNKNOWN
;
472 struct lttng_rotation_schedule
*
473 lttng_rotation_schedule_size_threshold_create(void)
475 struct lttng_rotation_schedule_size_threshold
*schedule
;
477 schedule
= zmalloc(sizeof(*schedule
));
482 schedule
->parent
.type
= LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD
;
484 return &schedule
->parent
;
487 enum lttng_rotation_status
488 lttng_rotation_schedule_size_threshold_get_threshold(
489 const struct lttng_rotation_schedule
*schedule
,
490 uint64_t *size_threshold_bytes
)
492 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
493 struct lttng_rotation_schedule_size_threshold
*size_schedule
;
495 if (!schedule
|| !size_threshold_bytes
||
496 schedule
->type
!= LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD
) {
497 status
= LTTNG_ROTATION_STATUS_INVALID
;
501 size_schedule
= container_of(schedule
,
502 struct lttng_rotation_schedule_size_threshold
,
504 if (size_schedule
->size
.set
) {
505 *size_threshold_bytes
= size_schedule
->size
.bytes
;
507 status
= LTTNG_ROTATION_STATUS_UNAVAILABLE
;
514 enum lttng_rotation_status
515 lttng_rotation_schedule_size_threshold_set_threshold(
516 struct lttng_rotation_schedule
*schedule
,
517 uint64_t size_threshold_bytes
)
519 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
520 struct lttng_rotation_schedule_size_threshold
*size_schedule
;
522 if (!schedule
|| size_threshold_bytes
== 0 ||
523 size_threshold_bytes
== -1ULL ||
524 schedule
->type
!= LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD
) {
525 status
= LTTNG_ROTATION_STATUS_INVALID
;
529 size_schedule
= container_of(schedule
,
530 struct lttng_rotation_schedule_size_threshold
,
532 size_schedule
->size
.bytes
= size_threshold_bytes
;
533 size_schedule
->size
.set
= true;
538 struct lttng_rotation_schedule
*
539 lttng_rotation_schedule_periodic_create(void)
541 struct lttng_rotation_schedule_periodic
*schedule
;
543 schedule
= zmalloc(sizeof(*schedule
));
548 schedule
->parent
.type
= LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC
;
550 return &schedule
->parent
;
553 enum lttng_rotation_status
554 lttng_rotation_schedule_periodic_get_period(
555 const struct lttng_rotation_schedule
*schedule
,
558 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
559 struct lttng_rotation_schedule_periodic
*periodic_schedule
;
561 if (!schedule
|| !period_us
||
562 schedule
->type
!= LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC
) {
563 status
= LTTNG_ROTATION_STATUS_INVALID
;
567 periodic_schedule
= container_of(schedule
,
568 struct lttng_rotation_schedule_periodic
,
570 if (periodic_schedule
->period
.set
) {
571 *period_us
= periodic_schedule
->period
.us
;
573 status
= LTTNG_ROTATION_STATUS_UNAVAILABLE
;
580 enum lttng_rotation_status
581 lttng_rotation_schedule_periodic_set_period(
582 struct lttng_rotation_schedule
*schedule
,
585 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
586 struct lttng_rotation_schedule_periodic
*periodic_schedule
;
588 if (!schedule
|| period_us
== 0 || period_us
== -1ULL ||
589 schedule
->type
!= LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC
) {
590 status
= LTTNG_ROTATION_STATUS_INVALID
;
594 periodic_schedule
= container_of(schedule
,
595 struct lttng_rotation_schedule_periodic
,
597 periodic_schedule
->period
.us
= period_us
;
598 periodic_schedule
->period
.set
= true;
603 void lttng_rotation_schedule_destroy(struct lttng_rotation_schedule
*schedule
)
611 void lttng_rotation_schedules_destroy(
612 struct lttng_rotation_schedules
*schedules
)
620 for (i
= 0; i
< schedules
->count
; i
++) {
621 lttng_rotation_schedule_destroy(schedules
->schedules
[i
]);
627 enum lttng_rotation_status
lttng_rotation_schedules_get_count(
628 const struct lttng_rotation_schedules
*schedules
,
631 enum lttng_rotation_status status
= LTTNG_ROTATION_STATUS_OK
;
633 if (!schedules
|| !count
) {
634 status
= LTTNG_ROTATION_STATUS_INVALID
;
638 *count
= schedules
->count
;
643 const struct lttng_rotation_schedule
*lttng_rotation_schedules_get_at_index(
644 const struct lttng_rotation_schedules
*schedules
,
647 const struct lttng_rotation_schedule
*schedule
= NULL
;
649 if (!schedules
|| index
>= schedules
->count
) {
653 schedule
= schedules
->schedules
[index
];
658 enum lttng_rotation_status
lttng_session_add_rotation_schedule(
659 const char *session_name
,
660 const struct lttng_rotation_schedule
*schedule
)
662 return lttng_rotation_update_schedule(session_name
, schedule
, true);
665 enum lttng_rotation_status
lttng_session_remove_rotation_schedule(
666 const char *session_name
,
667 const struct lttng_rotation_schedule
*schedule
)
669 return lttng_rotation_update_schedule(session_name
, schedule
, false);
672 int lttng_session_list_rotation_schedules(
673 const char *session_name
,
674 struct lttng_rotation_schedules
**schedules
)
676 return get_schedules(session_name
, schedules
);