2dbaa46a3eaf9d955b3d50f030c0504421aa3260
[lttng-tools.git] / src / lib / lttng-ctl / rotate.c
1 /*
2 * Copyright (C) 2017 Julien Desfossez <jdesfossez@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
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>
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>
18
19 #include "lttng-ctl-helper.h"
20
21 static
22 enum 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 }
52 end:
53 return status;
54
55 }
56
57 static
58 struct lttng_trace_archive_location *
59 create_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
84 enum 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;
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;
102 if (rotation_handle->archive_location ||
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 */
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;
119 goto end;
120 }
121 end:
122 free(info);
123 return status;
124 }
125
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)
129 {
130 enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
131 struct lttng_rotation_get_info_return *info = NULL;
132
133 if (!rotation_handle || !location) {
134 status = LTTNG_ROTATION_STATUS_INVALID;
135 goto end;
136 }
137
138 /* Use the cached location we got from a previous query. */
139 if (rotation_handle->archive_location) {
140 *location = rotation_handle->archive_location;
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
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;
159 goto end;
160 }
161 end:
162 free(info);
163 return status;
164 }
165
166 void lttng_rotation_handle_destroy(
167 struct lttng_rotation_handle *rotation_handle)
168 {
169 if (!rotation_handle) {
170 return;
171 }
172 lttng_trace_archive_location_destroy(rotation_handle->archive_location);
173 free(rotation_handle);
174 }
175
176 static
177 int init_rotation_handle(struct lttng_rotation_handle *rotation_handle,
178 const char *session_name,
179 struct lttng_rotate_session_return *rotate_return)
180 {
181 int ret;
182
183 ret = lttng_strncpy(rotation_handle->session_name, session_name,
184 sizeof(rotation_handle->session_name));
185 if (ret) {
186 goto end;
187 }
188
189 rotation_handle->rotation_id = rotate_return->rotation_id;
190 end:
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 */
199 int lttng_rotate_session(const char *session_name,
200 struct lttng_rotation_immediate_descriptor *descriptor,
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;
206 size_t session_name_len;
207
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)) {
216 ret = -LTTNG_ERR_INVALID;
217 goto end;
218 }
219
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));
224
225 ret = lttng_ctl_ask_sessiond(&lsm, (void **) &rotate_return);
226 if (ret <= 0) {
227 *rotation_handle = NULL;
228 goto end;
229 }
230
231 *rotation_handle = zmalloc(sizeof(struct lttng_rotation_handle));
232 if (!*rotation_handle) {
233 ret = -LTTNG_ERR_NOMEM;
234 goto end;
235 }
236
237 init_rotation_handle(*rotation_handle, session_name, rotate_return);
238
239 ret = 0;
240
241 end:
242 free(rotate_return);
243 return ret;
244 }
245
246 /*
247 * Update the automatic rotation parameters.
248 * 'add' as true enables the provided schedule, false removes the shedule.
249 *
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).
253 *
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.
258 *
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.
262 */
263 static
264 enum lttng_rotation_status lttng_rotation_update_schedule(
265 const char *session_name,
266 const struct lttng_rotation_schedule *schedule,
267 bool add)
268 {
269 struct lttcomm_session_msg lsm;
270 enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
271 int ret;
272
273 if (!session_name || !schedule) {
274 status = LTTNG_ROTATION_STATUS_INVALID;
275 goto end;
276 }
277
278 if (strlen(session_name) >= sizeof(lsm.session.name)) {
279 status = LTTNG_ROTATION_STATUS_INVALID;
280 goto end;
281 }
282
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));
287
288 lsm.u.rotation_set_schedule.type = (uint32_t) schedule->type;
289 switch (schedule->type) {
290 case LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD:
291 {
292 uint64_t threshold;
293
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;
299 }
300 goto end;
301 }
302 lsm.u.rotation_set_schedule.value = threshold;
303 lsm.u.rotation_set_schedule.set = !!add;
304 break;
305 }
306 case LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC:
307 {
308 uint64_t period;
309
310 status = lttng_rotation_schedule_periodic_get_period(
311 schedule, &period);
312 if (status != LTTNG_ROTATION_STATUS_OK) {
313 if (status == LTTNG_ROTATION_STATUS_UNAVAILABLE) {
314 status = LTTNG_ROTATION_STATUS_INVALID;
315 }
316 goto end;
317 }
318 lsm.u.rotation_set_schedule.value = period;
319 lsm.u.rotation_set_schedule.set = !!add;
320 break;
321 }
322 default:
323 status = LTTNG_ROTATION_STATUS_INVALID;
324 goto end;
325 }
326
327 ret = lttng_ctl_ask_sessiond(&lsm, NULL);
328 if (ret >= 0) {
329 goto end;
330 }
331
332 switch (-ret) {
333 case LTTNG_ERR_ROTATION_SCHEDULE_SET:
334 status = LTTNG_ROTATION_STATUS_SCHEDULE_ALREADY_SET;
335 break;
336 case LTTNG_ERR_ROTATION_SCHEDULE_NOT_SET:
337 status = LTTNG_ROTATION_STATUS_INVALID;
338 break;
339 default:
340 status = LTTNG_ROTATION_STATUS_ERROR;
341 }
342 end:
343 return status;
344 }
345
346 static
347 struct lttng_rotation_schedules *lttng_rotation_schedules_create(void)
348 {
349 return zmalloc(sizeof(struct lttng_rotation_schedules));
350 }
351
352 static
353 void lttng_schedules_add(struct lttng_rotation_schedules *schedules,
354 struct lttng_rotation_schedule *schedule)
355 {
356 schedules->schedules[schedules->count++] = schedule;
357 }
358
359 static
360 int get_schedules(const char *session_name,
361 struct lttng_rotation_schedules **_schedules)
362 {
363 int ret;
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;
368
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));
373
374 ret = lttng_ctl_ask_sessiond(&lsm, (void **) &schedules_comm);
375 if (ret < 0) {
376 goto end;
377 }
378
379 schedules = lttng_rotation_schedules_create();
380 if (!schedules) {
381 ret = -LTTNG_ERR_NOMEM;
382 goto end;
383 }
384
385 if (schedules_comm->periodic.set == 1) {
386 enum lttng_rotation_status status;
387
388 periodic = lttng_rotation_schedule_periodic_create();
389 if (!periodic) {
390 ret = -LTTNG_ERR_NOMEM;
391 goto end;
392 }
393
394 status = lttng_rotation_schedule_periodic_set_period(
395 periodic, schedules_comm->periodic.value);
396 if (status != LTTNG_ROTATION_STATUS_OK) {
397 /*
398 * This would imply that the session daemon returned
399 * an invalid periodic rotation schedule value.
400 */
401 ret = -LTTNG_ERR_UNK;
402 goto end;
403 }
404
405 lttng_schedules_add(schedules, periodic);
406 periodic = NULL;
407 }
408
409 if (schedules_comm->size.set == 1) {
410 enum lttng_rotation_status status;
411
412 size = lttng_rotation_schedule_size_threshold_create();
413 if (!size) {
414 ret = -LTTNG_ERR_NOMEM;
415 goto end;
416 }
417
418 status = lttng_rotation_schedule_size_threshold_set_threshold(
419 size, schedules_comm->size.value);
420 if (status != LTTNG_ROTATION_STATUS_OK) {
421 /*
422 * This would imply that the session daemon returned
423 * an invalid size threshold schedule value.
424 */
425 ret = -LTTNG_ERR_UNK;
426 goto end;
427 }
428
429 lttng_schedules_add(schedules, size);
430 size = NULL;
431 }
432
433 ret = LTTNG_OK;
434 end:
435 free(schedules_comm);
436 free(periodic);
437 free(size);
438 *_schedules = schedules;
439 return ret;
440 }
441
442 enum lttng_rotation_schedule_type lttng_rotation_schedule_get_type(
443 const struct lttng_rotation_schedule *schedule)
444 {
445 return schedule ? schedule->type : LTTNG_ROTATION_SCHEDULE_TYPE_UNKNOWN;
446 }
447
448 struct lttng_rotation_schedule *
449 lttng_rotation_schedule_size_threshold_create(void)
450 {
451 struct lttng_rotation_schedule_size_threshold *schedule;
452
453 schedule = zmalloc(sizeof(*schedule));
454 if (!schedule) {
455 goto end;
456 }
457
458 schedule->parent.type = LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD;
459 end:
460 return &schedule->parent;
461 }
462
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)
467 {
468 enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
469 struct lttng_rotation_schedule_size_threshold *size_schedule;
470
471 if (!schedule || !size_threshold_bytes ||
472 schedule->type != LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD) {
473 status = LTTNG_ROTATION_STATUS_INVALID;
474 goto end;
475 }
476
477 size_schedule = container_of(schedule,
478 struct lttng_rotation_schedule_size_threshold,
479 parent);
480 if (size_schedule->size.set) {
481 *size_threshold_bytes = size_schedule->size.bytes;
482 } else {
483 status = LTTNG_ROTATION_STATUS_UNAVAILABLE;
484 goto end;
485 }
486 end:
487 return status;
488 }
489
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)
494 {
495 enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
496 struct lttng_rotation_schedule_size_threshold *size_schedule;
497
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;
502 goto end;
503 }
504
505 size_schedule = container_of(schedule,
506 struct lttng_rotation_schedule_size_threshold,
507 parent);
508 size_schedule->size.bytes = size_threshold_bytes;
509 size_schedule->size.set = true;
510 end:
511 return status;
512 }
513
514 struct lttng_rotation_schedule *
515 lttng_rotation_schedule_periodic_create(void)
516 {
517 struct lttng_rotation_schedule_periodic *schedule;
518
519 schedule = zmalloc(sizeof(*schedule));
520 if (!schedule) {
521 goto end;
522 }
523
524 schedule->parent.type = LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC;
525 end:
526 return &schedule->parent;
527 }
528
529 enum lttng_rotation_status
530 lttng_rotation_schedule_periodic_get_period(
531 const struct lttng_rotation_schedule *schedule,
532 uint64_t *period_us)
533 {
534 enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
535 struct lttng_rotation_schedule_periodic *periodic_schedule;
536
537 if (!schedule || !period_us ||
538 schedule->type != LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC) {
539 status = LTTNG_ROTATION_STATUS_INVALID;
540 goto end;
541 }
542
543 periodic_schedule = container_of(schedule,
544 struct lttng_rotation_schedule_periodic,
545 parent);
546 if (periodic_schedule->period.set) {
547 *period_us = periodic_schedule->period.us;
548 } else {
549 status = LTTNG_ROTATION_STATUS_UNAVAILABLE;
550 goto end;
551 }
552 end:
553 return status;
554 }
555
556 enum lttng_rotation_status
557 lttng_rotation_schedule_periodic_set_period(
558 struct lttng_rotation_schedule *schedule,
559 uint64_t period_us)
560 {
561 enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
562 struct lttng_rotation_schedule_periodic *periodic_schedule;
563
564 if (!schedule || period_us == 0 || period_us == -1ULL ||
565 schedule->type != LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC) {
566 status = LTTNG_ROTATION_STATUS_INVALID;
567 goto end;
568 }
569
570 periodic_schedule = container_of(schedule,
571 struct lttng_rotation_schedule_periodic,
572 parent);
573 periodic_schedule->period.us = period_us;
574 periodic_schedule->period.set = true;
575 end:
576 return status;
577 }
578
579 void lttng_rotation_schedule_destroy(struct lttng_rotation_schedule *schedule)
580 {
581 if (!schedule) {
582 return;
583 }
584 free(schedule);
585 }
586
587 void lttng_rotation_schedules_destroy(
588 struct lttng_rotation_schedules *schedules)
589 {
590 unsigned int i;
591
592 if (!schedules) {
593 return;
594 }
595
596 for (i = 0; i < schedules->count; i++) {
597 lttng_rotation_schedule_destroy(schedules->schedules[i]);
598 }
599 free(schedules);
600 }
601
602
603 enum lttng_rotation_status lttng_rotation_schedules_get_count(
604 const struct lttng_rotation_schedules *schedules,
605 unsigned int *count)
606 {
607 enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
608
609 if (!schedules || !count) {
610 status = LTTNG_ROTATION_STATUS_INVALID;
611 goto end;
612 }
613
614 *count = schedules->count;
615 end:
616 return status;
617 }
618
619 const struct lttng_rotation_schedule *lttng_rotation_schedules_get_at_index(
620 const struct lttng_rotation_schedules *schedules,
621 unsigned int index)
622 {
623 const struct lttng_rotation_schedule *schedule = NULL;
624
625 if (!schedules || index >= schedules->count) {
626 goto end;
627 }
628
629 schedule = schedules->schedules[index];
630 end:
631 return schedule;
632 }
633
634 enum lttng_rotation_status lttng_session_add_rotation_schedule(
635 const char *session_name,
636 const struct lttng_rotation_schedule *schedule)
637 {
638 return lttng_rotation_update_schedule(session_name, schedule, true);
639 }
640
641 enum lttng_rotation_status lttng_session_remove_rotation_schedule(
642 const char *session_name,
643 const struct lttng_rotation_schedule *schedule)
644 {
645 return lttng_rotation_update_schedule(session_name, schedule, false);
646 }
647
648 int lttng_session_list_rotation_schedules(
649 const char *session_name,
650 struct lttng_rotation_schedules **schedules)
651 {
652 return get_schedules(session_name, schedules);
653 }
This page took 0.063077 seconds and 3 git commands to generate.