configure: add '-Wredundant-decls' to warning flags
[lttng-tools.git] / src / lib / lttng-ctl / rotate.cpp
CommitLineData
d68c9a04 1/*
ab5be9fa 2 * Copyright (C) 2017 Julien Desfossez <jdesfossez@efficios.com>
d68c9a04 3 *
ab5be9fa 4 * SPDX-License-Identifier: LGPL-2.1-only
d68c9a04 5 *
d68c9a04
JD
6 */
7
8#define _LGPL_SOURCE
d68c9a04
JD
9#include <string.h>
10
11#include <lttng/lttng-error.h>
12#include <lttng/rotation.h>
dd73d57b 13#include <lttng/location-internal.h>
d68c9a04
JD
14#include <lttng/rotate-internal.h>
15#include <common/sessiond-comm/sessiond-comm.h>
16#include <common/macros.h>
17
18#include "lttng-ctl-helper.h"
19
d68c9a04
JD
20static
21enum lttng_rotation_status ask_rotation_info(
22 struct lttng_rotation_handle *rotation_handle,
23 struct lttng_rotation_get_info_return **info)
24{
25 /* lsm.get_rotation_state.rotation_id */
26 struct lttcomm_session_msg lsm;
27 enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
28 int ret;
29
30 if (!rotation_handle || !info) {
31 status = LTTNG_ROTATION_STATUS_INVALID;
32 goto end;
33 }
34
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;
38
39 ret = lttng_strncpy(lsm.session.name, rotation_handle->session_name,
40 sizeof(lsm.session.name));
41 if (ret) {
42 status = LTTNG_ROTATION_STATUS_INVALID;
43 goto end;
44 }
45
46 ret = lttng_ctl_ask_sessiond(&lsm, (void **) info);
47 if (ret < 0) {
48 status = LTTNG_ROTATION_STATUS_ERROR;
49 goto end;
50 }
51end:
52 return status;
53
54}
55
dd73d57b
JG
56static
57struct lttng_trace_archive_location *
58create_trace_archive_location_from_get_info(
59 const struct lttng_rotation_get_info_return *info)
60{
61 struct lttng_trace_archive_location *location;
62
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);
67 break;
68 case LTTNG_TRACE_ARCHIVE_LOCATION_TYPE_RELAY:
69 location = lttng_trace_archive_location_relay_create(
70 info->location.relay.host,
4bd69c5f 71 (lttng_trace_archive_location_relay_protocol_type) info->location.relay.protocol,
dd73d57b
JG
72 info->location.relay.ports.control,
73 info->location.relay.ports.data,
74 info->location.relay.relative_path);
75 break;
76 default:
77 location = NULL;
78 break;
79 }
80 return location;
81}
82
d68c9a04
JD
83enum lttng_rotation_status lttng_rotation_handle_get_state(
84 struct lttng_rotation_handle *rotation_handle,
85 enum lttng_rotation_state *state)
86{
87 enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
88 struct lttng_rotation_get_info_return *info = NULL;
d68c9a04
JD
89
90 if (!rotation_handle || !state) {
91 status = LTTNG_ROTATION_STATUS_INVALID;
92 goto end;
93 }
94
95 status = ask_rotation_info(rotation_handle, &info);
96 if (status != LTTNG_ROTATION_STATUS_OK) {
97 goto end;
98 }
99
100 *state = (enum lttng_rotation_state) info->status;
dd73d57b 101 if (rotation_handle->archive_location ||
d68c9a04
JD
102 *state != LTTNG_ROTATION_STATE_COMPLETED) {
103 /*
104 * The path is only provided by the sessiond once
105 * the session rotation is completed, but not expired.
106 */
107 goto end;
108 }
109
110 /*
111 * Cache the location since the rotation may expire before the user
112 * has a chance to query it.
113 */
dd73d57b
JG
114 rotation_handle->archive_location =
115 create_trace_archive_location_from_get_info(info);
116 if (!rotation_handle->archive_location) {
d68c9a04
JD
117 status = LTTNG_ROTATION_STATUS_ERROR;
118 goto end;
119 }
d68c9a04
JD
120end:
121 free(info);
122 return status;
123}
124
dd73d57b 125enum lttng_rotation_status lttng_rotation_handle_get_archive_location(
d68c9a04 126 struct lttng_rotation_handle *rotation_handle,
dd73d57b 127 const struct lttng_trace_archive_location **location)
d68c9a04 128{
d68c9a04
JD
129 enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
130 struct lttng_rotation_get_info_return *info = NULL;
131
dd73d57b 132 if (!rotation_handle || !location) {
d68c9a04
JD
133 status = LTTNG_ROTATION_STATUS_INVALID;
134 goto end;
135 }
136
137 /* Use the cached location we got from a previous query. */
dd73d57b
JG
138 if (rotation_handle->archive_location) {
139 *location = rotation_handle->archive_location;
d68c9a04
JD
140 goto end;
141 }
142
143 status = ask_rotation_info(rotation_handle, &info);
144 if (status != LTTNG_ROTATION_STATUS_OK) {
145 goto end;
146 }
147
148 if ((enum lttng_rotation_state) info->status !=
149 LTTNG_ROTATION_STATE_COMPLETED) {
150 status = LTTNG_ROTATION_STATUS_UNAVAILABLE;
151 goto end;
152 }
153
dd73d57b
JG
154 rotation_handle->archive_location =
155 create_trace_archive_location_from_get_info(info);
156 if (!rotation_handle->archive_location) {
d68c9a04
JD
157 status = LTTNG_ROTATION_STATUS_ERROR;
158 goto end;
159 }
d68c9a04
JD
160end:
161 free(info);
162 return status;
163}
164
165void lttng_rotation_handle_destroy(
166 struct lttng_rotation_handle *rotation_handle)
167{
06b180a1
JR
168 if (!rotation_handle) {
169 return;
170 }
d3740619 171 lttng_trace_archive_location_put(rotation_handle->archive_location);
d68c9a04
JD
172 free(rotation_handle);
173}
174
175static
176int init_rotation_handle(struct lttng_rotation_handle *rotation_handle,
dbd512ea 177 const char *session_name,
66ea93b1 178 struct lttng_rotate_session_return *rotate_return)
d68c9a04
JD
179{
180 int ret;
181
dbd512ea 182 ret = lttng_strncpy(rotation_handle->session_name, session_name,
d68c9a04
JD
183 sizeof(rotation_handle->session_name));
184 if (ret) {
185 goto end;
186 }
187
188 rotation_handle->rotation_id = rotate_return->rotation_id;
189end:
190 return ret;
191}
192
193/*
194 * Rotate the output folder of the session.
195 *
196 * Return 0 on success else a negative LTTng error code.
197 */
dbd512ea 198int lttng_rotate_session(const char *session_name,
66ea93b1 199 struct lttng_rotation_immediate_descriptor *descriptor,
d68c9a04
JD
200 struct lttng_rotation_handle **rotation_handle)
201{
202 struct lttcomm_session_msg lsm;
203 struct lttng_rotate_session_return *rotate_return = NULL;
204 int ret;
dbd512ea 205 size_t session_name_len;
d68c9a04 206
dbd512ea
JG
207 if (!session_name) {
208 ret = -LTTNG_ERR_INVALID;
209 goto end;
210 }
211
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)) {
d68c9a04
JD
215 ret = -LTTNG_ERR_INVALID;
216 goto end;
217 }
218
219 memset(&lsm, 0, sizeof(lsm));
220 lsm.cmd_type = LTTNG_ROTATE_SESSION;
e1b624d0
JG
221
222 ret = lttng_strncpy(lsm.session.name, session_name,
223 sizeof(lsm.session.name));
224 /* Source length already validated. */
a0377dfe 225 LTTNG_ASSERT(ret == 0);
d68c9a04
JD
226
227 ret = lttng_ctl_ask_sessiond(&lsm, (void **) &rotate_return);
1320cab1 228 if (ret <= 0) {
d68c9a04
JD
229 *rotation_handle = NULL;
230 goto end;
231 }
232
4bd69c5f 233 *rotation_handle = (lttng_rotation_handle *) zmalloc(sizeof(struct lttng_rotation_handle));
d68c9a04
JD
234 if (!*rotation_handle) {
235 ret = -LTTNG_ERR_NOMEM;
236 goto end;
237 }
238
66ea93b1 239 init_rotation_handle(*rotation_handle, session_name, rotate_return);
d68c9a04
JD
240
241 ret = 0;
242
243end:
244 free(rotate_return);
245 return ret;
246}
259c2674
JD
247
248/*
66ea93b1
JG
249 * Update the automatic rotation parameters.
250 * 'add' as true enables the provided schedule, false removes the shedule.
251 *
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).
255 *
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.
260 *
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.
259c2674 264 */
66ea93b1
JG
265static
266enum lttng_rotation_status lttng_rotation_update_schedule(
267 const char *session_name,
268 const struct lttng_rotation_schedule *schedule,
269 bool add)
259c2674
JD
270{
271 struct lttcomm_session_msg lsm;
66ea93b1 272 enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
259c2674
JD
273 int ret;
274
66ea93b1
JG
275 if (!session_name || !schedule) {
276 status = LTTNG_ROTATION_STATUS_INVALID;
dbd512ea
JG
277 goto end;
278 }
279
280 if (strlen(session_name) >= sizeof(lsm.session.name)) {
66ea93b1 281 status = LTTNG_ROTATION_STATUS_INVALID;
259c2674
JD
282 goto end;
283 }
284
285 memset(&lsm, 0, sizeof(lsm));
286 lsm.cmd_type = LTTNG_ROTATION_SET_SCHEDULE;
e1b624d0 287 ret = lttng_strncpy(lsm.session.name, session_name,
259c2674 288 sizeof(lsm.session.name));
e1b624d0 289 /* Source length already validated. */
a0377dfe 290 LTTNG_ASSERT(ret == 0);
66ea93b1
JG
291
292 lsm.u.rotation_set_schedule.type = (uint32_t) schedule->type;
293 switch (schedule->type) {
294 case LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD:
295 {
7370c955
JG
296 uint64_t threshold;
297
66ea93b1 298 status = lttng_rotation_schedule_size_threshold_get_threshold(
7370c955 299 schedule, &threshold);
66ea93b1 300 if (status != LTTNG_ROTATION_STATUS_OK) {
ed9f1fb2
JG
301 if (status == LTTNG_ROTATION_STATUS_UNAVAILABLE) {
302 status = LTTNG_ROTATION_STATUS_INVALID;
303 }
66ea93b1
JG
304 goto end;
305 }
7370c955 306 lsm.u.rotation_set_schedule.value = threshold;
66ea93b1
JG
307 lsm.u.rotation_set_schedule.set = !!add;
308 break;
309 }
310 case LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC:
311 {
7370c955
JG
312 uint64_t period;
313
66ea93b1 314 status = lttng_rotation_schedule_periodic_get_period(
7370c955 315 schedule, &period);
66ea93b1 316 if (status != LTTNG_ROTATION_STATUS_OK) {
ed9f1fb2
JG
317 if (status == LTTNG_ROTATION_STATUS_UNAVAILABLE) {
318 status = LTTNG_ROTATION_STATUS_INVALID;
319 }
66ea93b1
JG
320 goto end;
321 }
7370c955 322 lsm.u.rotation_set_schedule.value = period;
66ea93b1
JG
323 lsm.u.rotation_set_schedule.set = !!add;
324 break;
325 }
326 default:
327 status = LTTNG_ROTATION_STATUS_INVALID;
328 goto end;
329 }
259c2674
JD
330
331 ret = lttng_ctl_ask_sessiond(&lsm, NULL);
66ea93b1
JG
332 if (ret >= 0) {
333 goto end;
334 }
335
336 switch (-ret) {
337 case LTTNG_ERR_ROTATION_SCHEDULE_SET:
338 status = LTTNG_ROTATION_STATUS_SCHEDULE_ALREADY_SET;
339 break;
340 case LTTNG_ERR_ROTATION_SCHEDULE_NOT_SET:
341 status = LTTNG_ROTATION_STATUS_INVALID;
342 break;
343 default:
344 status = LTTNG_ROTATION_STATUS_ERROR;
345 }
259c2674 346end:
66ea93b1
JG
347 return status;
348}
349
350static
351struct lttng_rotation_schedules *lttng_rotation_schedules_create(void)
352{
4bd69c5f 353 return (lttng_rotation_schedules *) zmalloc(sizeof(struct lttng_rotation_schedules));
259c2674 354}
329f3443 355
66ea93b1
JG
356static
357void lttng_schedules_add(struct lttng_rotation_schedules *schedules,
358 struct lttng_rotation_schedule *schedule)
359{
360 schedules->schedules[schedules->count++] = schedule;
361}
362
363static
364int get_schedules(const char *session_name,
365 struct lttng_rotation_schedules **_schedules)
329f3443 366{
329f3443 367 int ret;
66ea93b1 368 struct lttcomm_session_msg lsm;
25357057 369 struct lttng_session_list_schedules_return *schedules_comm = NULL;
66ea93b1
JG
370 struct lttng_rotation_schedules *schedules = NULL;
371 struct lttng_rotation_schedule *periodic = NULL, *size = NULL;
329f3443 372
e1b624d0
JG
373 if (!session_name) {
374 ret = -LTTNG_ERR_INVALID;
375 goto end;
376 }
377
329f3443 378 memset(&lsm, 0, sizeof(lsm));
66ea93b1 379 lsm.cmd_type = LTTNG_SESSION_LIST_ROTATION_SCHEDULES;
e1b624d0 380 ret = lttng_strncpy(lsm.session.name, session_name,
329f3443 381 sizeof(lsm.session.name));
e1b624d0
JG
382 if (ret) {
383 ret = -LTTNG_ERR_INVALID;
384 goto end;
385 }
329f3443 386
66ea93b1 387 ret = lttng_ctl_ask_sessiond(&lsm, (void **) &schedules_comm);
329f3443 388 if (ret < 0) {
329f3443
JD
389 goto end;
390 }
391
66ea93b1
JG
392 schedules = lttng_rotation_schedules_create();
393 if (!schedules) {
394 ret = -LTTNG_ERR_NOMEM;
395 goto end;
396 }
397
398 if (schedules_comm->periodic.set == 1) {
399 enum lttng_rotation_status status;
400
401 periodic = lttng_rotation_schedule_periodic_create();
402 if (!periodic) {
403 ret = -LTTNG_ERR_NOMEM;
404 goto end;
405 }
406
407 status = lttng_rotation_schedule_periodic_set_period(
408 periodic, schedules_comm->periodic.value);
409 if (status != LTTNG_ROTATION_STATUS_OK) {
410 /*
411 * This would imply that the session daemon returned
412 * an invalid periodic rotation schedule value.
413 */
414 ret = -LTTNG_ERR_UNK;
415 goto end;
416 }
417
418 lttng_schedules_add(schedules, periodic);
419 periodic = NULL;
420 }
421
422 if (schedules_comm->size.set == 1) {
423 enum lttng_rotation_status status;
424
425 size = lttng_rotation_schedule_size_threshold_create();
426 if (!size) {
427 ret = -LTTNG_ERR_NOMEM;
428 goto end;
429 }
430
431 status = lttng_rotation_schedule_size_threshold_set_threshold(
432 size, schedules_comm->size.value);
433 if (status != LTTNG_ROTATION_STATUS_OK) {
434 /*
435 * This would imply that the session daemon returned
436 * an invalid size threshold schedule value.
437 */
438 ret = -LTTNG_ERR_UNK;
439 goto end;
440 }
441
442 lttng_schedules_add(schedules, size);
443 size = NULL;
444 }
445
446 ret = LTTNG_OK;
329f3443 447end:
66ea93b1
JG
448 free(schedules_comm);
449 free(periodic);
450 free(size);
451 *_schedules = schedules;
329f3443
JD
452 return ret;
453}
454
66ea93b1
JG
455enum lttng_rotation_schedule_type lttng_rotation_schedule_get_type(
456 const struct lttng_rotation_schedule *schedule)
329f3443 457{
66ea93b1
JG
458 return schedule ? schedule->type : LTTNG_ROTATION_SCHEDULE_TYPE_UNKNOWN;
459}
329f3443 460
66ea93b1
JG
461struct lttng_rotation_schedule *
462lttng_rotation_schedule_size_threshold_create(void)
463{
464 struct lttng_rotation_schedule_size_threshold *schedule;
329f3443 465
4bd69c5f 466 schedule = (lttng_rotation_schedule_size_threshold *) zmalloc(sizeof(*schedule));
66ea93b1 467 if (!schedule) {
329f3443
JD
468 goto end;
469 }
470
66ea93b1
JG
471 schedule->parent.type = LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD;
472end:
473 return &schedule->parent;
474}
475
476enum lttng_rotation_status
477lttng_rotation_schedule_size_threshold_get_threshold(
478 const struct lttng_rotation_schedule *schedule,
479 uint64_t *size_threshold_bytes)
480{
481 enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
482 struct lttng_rotation_schedule_size_threshold *size_schedule;
329f3443 483
ed9f1fb2
JG
484 if (!schedule || !size_threshold_bytes ||
485 schedule->type != LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD) {
66ea93b1
JG
486 status = LTTNG_ROTATION_STATUS_INVALID;
487 goto end;
488 }
489
490 size_schedule = container_of(schedule,
491 struct lttng_rotation_schedule_size_threshold,
492 parent);
493 if (size_schedule->size.set) {
494 *size_threshold_bytes = size_schedule->size.bytes;
495 } else {
496 status = LTTNG_ROTATION_STATUS_UNAVAILABLE;
497 goto end;
498 }
499end:
500 return status;
501}
502
503enum lttng_rotation_status
504lttng_rotation_schedule_size_threshold_set_threshold(
505 struct lttng_rotation_schedule *schedule,
506 uint64_t size_threshold_bytes)
507{
508 enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
509 struct lttng_rotation_schedule_size_threshold *size_schedule;
510
511 if (!schedule || size_threshold_bytes == 0 ||
ed9f1fb2
JG
512 size_threshold_bytes == -1ULL ||
513 schedule->type != LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD) {
66ea93b1
JG
514 status = LTTNG_ROTATION_STATUS_INVALID;
515 goto end;
516 }
329f3443 517
66ea93b1
JG
518 size_schedule = container_of(schedule,
519 struct lttng_rotation_schedule_size_threshold,
520 parent);
521 size_schedule->size.bytes = size_threshold_bytes;
522 size_schedule->size.set = true;
329f3443 523end:
66ea93b1
JG
524 return status;
525}
526
527struct lttng_rotation_schedule *
528lttng_rotation_schedule_periodic_create(void)
529{
530 struct lttng_rotation_schedule_periodic *schedule;
531
4bd69c5f 532 schedule = (lttng_rotation_schedule_periodic *) zmalloc(sizeof(*schedule));
66ea93b1
JG
533 if (!schedule) {
534 goto end;
535 }
536
537 schedule->parent.type = LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC;
538end:
539 return &schedule->parent;
540}
541
542enum lttng_rotation_status
543lttng_rotation_schedule_periodic_get_period(
544 const struct lttng_rotation_schedule *schedule,
545 uint64_t *period_us)
546{
547 enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
548 struct lttng_rotation_schedule_periodic *periodic_schedule;
549
ed9f1fb2
JG
550 if (!schedule || !period_us ||
551 schedule->type != LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC) {
66ea93b1
JG
552 status = LTTNG_ROTATION_STATUS_INVALID;
553 goto end;
554 }
555
556 periodic_schedule = container_of(schedule,
557 struct lttng_rotation_schedule_periodic,
558 parent);
559 if (periodic_schedule->period.set) {
560 *period_us = periodic_schedule->period.us;
561 } else {
562 status = LTTNG_ROTATION_STATUS_UNAVAILABLE;
563 goto end;
564 }
565end:
566 return status;
567}
568
569enum lttng_rotation_status
570lttng_rotation_schedule_periodic_set_period(
571 struct lttng_rotation_schedule *schedule,
572 uint64_t period_us)
573{
574 enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
575 struct lttng_rotation_schedule_periodic *periodic_schedule;
576
ed9f1fb2
JG
577 if (!schedule || period_us == 0 || period_us == -1ULL ||
578 schedule->type != LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC) {
66ea93b1
JG
579 status = LTTNG_ROTATION_STATUS_INVALID;
580 goto end;
581 }
582
583 periodic_schedule = container_of(schedule,
584 struct lttng_rotation_schedule_periodic,
585 parent);
586 periodic_schedule->period.us = period_us;
587 periodic_schedule->period.set = true;
588end:
589 return status;
590}
591
592void lttng_rotation_schedule_destroy(struct lttng_rotation_schedule *schedule)
593{
594 if (!schedule) {
595 return;
596 }
597 free(schedule);
598}
599
600void lttng_rotation_schedules_destroy(
601 struct lttng_rotation_schedules *schedules)
602{
603 unsigned int i;
604
605 if (!schedules) {
606 return;
607 }
608
609 for (i = 0; i < schedules->count; i++) {
610 lttng_rotation_schedule_destroy(schedules->schedules[i]);
611 }
612 free(schedules);
613}
614
615
616enum lttng_rotation_status lttng_rotation_schedules_get_count(
617 const struct lttng_rotation_schedules *schedules,
618 unsigned int *count)
619{
620 enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
621
622 if (!schedules || !count) {
623 status = LTTNG_ROTATION_STATUS_INVALID;
624 goto end;
625 }
626
627 *count = schedules->count;
628end:
629 return status;
630}
631
632const struct lttng_rotation_schedule *lttng_rotation_schedules_get_at_index(
633 const struct lttng_rotation_schedules *schedules,
634 unsigned int index)
635{
636 const struct lttng_rotation_schedule *schedule = NULL;
637
638 if (!schedules || index >= schedules->count) {
639 goto end;
640 }
641
642 schedule = schedules->schedules[index];
643end:
644 return schedule;
645}
646
647enum lttng_rotation_status lttng_session_add_rotation_schedule(
648 const char *session_name,
649 const struct lttng_rotation_schedule *schedule)
650{
651 return lttng_rotation_update_schedule(session_name, schedule, true);
652}
653
654enum lttng_rotation_status lttng_session_remove_rotation_schedule(
655 const char *session_name,
656 const struct lttng_rotation_schedule *schedule)
657{
658 return lttng_rotation_update_schedule(session_name, schedule, false);
659}
660
661int lttng_session_list_rotation_schedules(
662 const char *session_name,
663 struct lttng_rotation_schedules **schedules)
664{
665 return get_schedules(session_name, schedules);
329f3443 666}
This page took 0.065956 seconds and 4 git commands to generate.