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