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