c62b5b38a1274ba25e3b94356f14f316478e475b
[lttng-tools.git] / src / common / conditions / session-rotation.cpp
1 /*
2 * Copyright (C) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8 #include <common/error.hpp>
9 #include <common/macros.hpp>
10 #include <common/mi-lttng.hpp>
11
12 #include <lttng/condition/condition-internal.hpp>
13 #include <lttng/condition/session-rotation-internal.hpp>
14 #include <lttng/location-internal.hpp>
15
16 #include <stdbool.h>
17
18 static bool lttng_condition_session_rotation_validate(const struct lttng_condition *condition);
19 static int lttng_condition_session_rotation_serialize(const struct lttng_condition *condition,
20 struct lttng_payload *payload);
21 static bool lttng_condition_session_rotation_is_equal(const struct lttng_condition *_a,
22 const struct lttng_condition *_b);
23 static void lttng_condition_session_rotation_destroy(struct lttng_condition *condition);
24
25 static enum lttng_error_code
26 lttng_condition_session_rotation_mi_serialize(const struct lttng_condition *condition,
27 struct mi_writer *writer);
28
29 static const struct lttng_condition rotation_condition_template = {
30 {},
31 LTTNG_CONDITION_TYPE_UNKNOWN, /* type unset, shall be set on creation. */
32 lttng_condition_session_rotation_validate,
33 lttng_condition_session_rotation_serialize,
34 lttng_condition_session_rotation_is_equal,
35 lttng_condition_session_rotation_destroy,
36 lttng_condition_session_rotation_mi_serialize,
37 };
38
39 static int lttng_evaluation_session_rotation_serialize(const struct lttng_evaluation *evaluation,
40 struct lttng_payload *payload);
41 static void lttng_evaluation_session_rotation_destroy(struct lttng_evaluation *evaluation);
42
43 static const struct lttng_evaluation rotation_evaluation_template = {
44 LTTNG_CONDITION_TYPE_UNKNOWN, /* type unset, shall be set on creation. */
45 lttng_evaluation_session_rotation_serialize,
46 lttng_evaluation_session_rotation_destroy,
47 };
48
49 static bool is_rotation_condition(const struct lttng_condition *condition)
50 {
51 enum lttng_condition_type type = lttng_condition_get_type(condition);
52
53 return type == LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING ||
54 type == LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED;
55 }
56
57 static bool is_rotation_evaluation(const struct lttng_evaluation *evaluation)
58 {
59 enum lttng_condition_type type = lttng_evaluation_get_type(evaluation);
60
61 return type == LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING ||
62 type == LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED;
63 }
64
65 static bool lttng_condition_session_rotation_validate(const struct lttng_condition *condition)
66 {
67 bool valid = false;
68 struct lttng_condition_session_rotation *rotation;
69
70 if (!condition) {
71 goto end;
72 }
73
74 rotation = lttng::utils::container_of(condition, &lttng_condition_session_rotation::parent);
75 if (!rotation->session_name) {
76 ERR("Invalid session rotation condition: a target session name must be set.");
77 goto end;
78 }
79
80 valid = true;
81 end:
82 return valid;
83 }
84
85 static int lttng_condition_session_rotation_serialize(const struct lttng_condition *condition,
86 struct lttng_payload *payload)
87 {
88 int ret;
89 size_t session_name_len;
90 struct lttng_condition_session_rotation *rotation;
91 struct lttng_condition_session_rotation_comm rotation_comm;
92
93 if (!condition || !is_rotation_condition(condition)) {
94 ret = -1;
95 goto end;
96 }
97
98 DBG("Serializing session rotation condition");
99 rotation = lttng::utils::container_of(condition, &lttng_condition_session_rotation::parent);
100
101 session_name_len = strlen(rotation->session_name) + 1;
102 if (session_name_len > LTTNG_NAME_MAX) {
103 ret = -1;
104 goto end;
105 }
106
107 rotation_comm.session_name_len = session_name_len;
108 ret = lttng_dynamic_buffer_append(&payload->buffer, &rotation_comm, sizeof(rotation_comm));
109 if (ret) {
110 goto end;
111 }
112 ret = lttng_dynamic_buffer_append(
113 &payload->buffer, rotation->session_name, session_name_len);
114 if (ret) {
115 goto end;
116 }
117 end:
118 return ret;
119 }
120
121 static bool lttng_condition_session_rotation_is_equal(const struct lttng_condition *_a,
122 const struct lttng_condition *_b)
123 {
124 bool is_equal = false;
125 struct lttng_condition_session_rotation *a, *b;
126
127 a = lttng::utils::container_of(_a, &lttng_condition_session_rotation::parent);
128 b = lttng::utils::container_of(_b, &lttng_condition_session_rotation::parent);
129
130 /* Both session names must be set or both must be unset. */
131 if ((a->session_name && !b->session_name) || (!a->session_name && b->session_name)) {
132 WARN("Comparing session rotation conditions with uninitialized session names.");
133 goto end;
134 }
135
136 if (a->session_name && b->session_name && strcmp(a->session_name, b->session_name)) {
137 goto end;
138 }
139
140 is_equal = true;
141 end:
142 return is_equal;
143 }
144
145 static void lttng_condition_session_rotation_destroy(struct lttng_condition *condition)
146 {
147 struct lttng_condition_session_rotation *rotation;
148
149 rotation = lttng::utils::container_of(condition, &lttng_condition_session_rotation::parent);
150
151 free(rotation->session_name);
152 free(rotation);
153 }
154
155 static struct lttng_condition *
156 lttng_condition_session_rotation_create(enum lttng_condition_type type)
157 {
158 struct lttng_condition_session_rotation *condition;
159
160 condition = zmalloc<lttng_condition_session_rotation>();
161 if (!condition) {
162 return nullptr;
163 }
164
165 memcpy(&condition->parent, &rotation_condition_template, sizeof(condition->parent));
166 lttng_condition_init(&condition->parent, type);
167 return &condition->parent;
168 }
169
170 struct lttng_condition *lttng_condition_session_rotation_ongoing_create(void)
171 {
172 return lttng_condition_session_rotation_create(
173 LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING);
174 }
175
176 struct lttng_condition *lttng_condition_session_rotation_completed_create(void)
177 {
178 return lttng_condition_session_rotation_create(
179 LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED);
180 }
181
182 static ssize_t init_condition_from_payload(struct lttng_condition *condition,
183 struct lttng_payload_view *src_view)
184 {
185 ssize_t ret, condition_size;
186 enum lttng_condition_status status;
187 const char *session_name;
188 struct lttng_buffer_view name_view;
189 const struct lttng_condition_session_rotation_comm *condition_comm;
190 struct lttng_payload_view condition_comm_view =
191 lttng_payload_view_from_view(src_view, 0, sizeof(*condition_comm));
192
193 if (!lttng_payload_view_is_valid(&condition_comm_view)) {
194 ERR("Failed to initialize from malformed condition buffer: buffer too short to contain header");
195 ret = -1;
196 goto end;
197 }
198
199 condition_comm = (typeof(condition_comm)) src_view->buffer.data;
200 name_view = lttng_buffer_view_from_view(
201 &src_view->buffer, sizeof(*condition_comm), condition_comm->session_name_len);
202
203 if (!lttng_buffer_view_is_valid(&name_view)) {
204 ERR("Failed to initialize from malformed condition buffer: buffer too short to contain session name");
205 ret = -1;
206 goto end;
207 }
208
209 if (condition_comm->session_name_len > LTTNG_NAME_MAX) {
210 ERR("Failed to initialize from malformed condition buffer: name exceeds LTTNG_MAX_NAME");
211 ret = -1;
212 goto end;
213 }
214
215 session_name = name_view.data;
216 if (*(session_name + condition_comm->session_name_len - 1) != '\0') {
217 ERR("Malformed session name encountered in condition buffer");
218 ret = -1;
219 goto end;
220 }
221
222 status = lttng_condition_session_rotation_set_session_name(condition, session_name);
223 if (status != LTTNG_CONDITION_STATUS_OK) {
224 ERR("Failed to set buffer consumed session name");
225 ret = -1;
226 goto end;
227 }
228
229 if (!lttng_condition_validate(condition)) {
230 ret = -1;
231 goto end;
232 }
233
234 condition_size = sizeof(*condition_comm) + (ssize_t) condition_comm->session_name_len;
235 ret = condition_size;
236 end:
237 return ret;
238 }
239
240 static ssize_t
241 lttng_condition_session_rotation_create_from_payload(struct lttng_payload_view *view,
242 struct lttng_condition **_condition,
243 enum lttng_condition_type type)
244 {
245 ssize_t ret;
246 struct lttng_condition *condition = nullptr;
247
248 switch (type) {
249 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
250 condition = lttng_condition_session_rotation_ongoing_create();
251 break;
252 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
253 condition = lttng_condition_session_rotation_completed_create();
254 break;
255 default:
256 ret = -1;
257 goto error;
258 }
259
260 if (!_condition || !condition) {
261 ret = -1;
262 goto error;
263 }
264
265 ret = init_condition_from_payload(condition, view);
266 if (ret < 0) {
267 goto error;
268 }
269
270 *_condition = condition;
271 return ret;
272 error:
273 lttng_condition_destroy(condition);
274 return ret;
275 }
276
277 ssize_t
278 lttng_condition_session_rotation_ongoing_create_from_payload(struct lttng_payload_view *view,
279 struct lttng_condition **condition)
280 {
281 return lttng_condition_session_rotation_create_from_payload(
282 view, condition, LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING);
283 }
284
285 ssize_t
286 lttng_condition_session_rotation_completed_create_from_payload(struct lttng_payload_view *view,
287 struct lttng_condition **condition)
288 {
289 return lttng_condition_session_rotation_create_from_payload(
290 view, condition, LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED);
291 }
292
293 static struct lttng_evaluation *lttng_evaluation_session_rotation_create(
294 enum lttng_condition_type type, uint64_t id, struct lttng_trace_archive_location *location)
295 {
296 struct lttng_evaluation_session_rotation *evaluation;
297
298 evaluation = zmalloc<lttng_evaluation_session_rotation>();
299 if (!evaluation) {
300 return nullptr;
301 }
302
303 memcpy(&evaluation->parent, &rotation_evaluation_template, sizeof(evaluation->parent));
304 lttng_evaluation_init(&evaluation->parent, type);
305 evaluation->id = id;
306 if (location) {
307 lttng_trace_archive_location_get(location);
308 }
309 evaluation->location = location;
310 return &evaluation->parent;
311 }
312
313 static ssize_t create_evaluation_from_payload(enum lttng_condition_type type,
314 struct lttng_payload_view *view,
315 struct lttng_evaluation **_evaluation)
316 {
317 ssize_t ret, size;
318 struct lttng_evaluation *evaluation = nullptr;
319 struct lttng_trace_archive_location *location = nullptr;
320 const struct lttng_evaluation_session_rotation_comm *comm;
321 struct lttng_payload_view comm_view = lttng_payload_view_from_view(view, 0, sizeof(*comm));
322
323 if (!lttng_payload_view_is_valid(&comm_view)) {
324 goto error;
325 }
326
327 comm = (typeof(comm)) comm_view.buffer.data;
328 size = sizeof(*comm);
329 if (comm->has_location) {
330 const struct lttng_buffer_view location_view =
331 lttng_buffer_view_from_view(&view->buffer, sizeof(*comm), -1);
332
333 if (!lttng_buffer_view_is_valid(&location_view)) {
334 goto error;
335 }
336
337 ret = lttng_trace_archive_location_create_from_buffer(&location_view, &location);
338 if (ret < 0) {
339 goto error;
340 }
341 size += ret;
342 }
343
344 evaluation = lttng_evaluation_session_rotation_create(type, comm->id, location);
345 if (!evaluation) {
346 goto error;
347 }
348
349 lttng_trace_archive_location_put(location);
350 ret = size;
351 *_evaluation = evaluation;
352 return ret;
353 error:
354 lttng_trace_archive_location_put(location);
355 evaluation = nullptr;
356 return -1;
357 }
358
359 static ssize_t
360 lttng_evaluation_session_rotation_create_from_payload(enum lttng_condition_type type,
361 struct lttng_payload_view *view,
362 struct lttng_evaluation **_evaluation)
363 {
364 ssize_t ret;
365 struct lttng_evaluation *evaluation = nullptr;
366
367 if (!_evaluation) {
368 ret = -1;
369 goto error;
370 }
371
372 ret = create_evaluation_from_payload(type, view, &evaluation);
373 if (ret < 0) {
374 goto error;
375 }
376
377 *_evaluation = evaluation;
378 return ret;
379 error:
380 lttng_evaluation_destroy(evaluation);
381 return ret;
382 }
383
384 ssize_t
385 lttng_evaluation_session_rotation_ongoing_create_from_payload(struct lttng_payload_view *view,
386 struct lttng_evaluation **evaluation)
387 {
388 return lttng_evaluation_session_rotation_create_from_payload(
389 LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING, view, evaluation);
390 }
391
392 ssize_t lttng_evaluation_session_rotation_completed_create_from_payload(
393 struct lttng_payload_view *view, struct lttng_evaluation **evaluation)
394 {
395 return lttng_evaluation_session_rotation_create_from_payload(
396 LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED, view, evaluation);
397 }
398
399 struct lttng_evaluation *lttng_evaluation_session_rotation_ongoing_create(uint64_t id)
400 {
401 return lttng_evaluation_session_rotation_create(
402 LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING, id, nullptr);
403 }
404
405 struct lttng_evaluation *
406 lttng_evaluation_session_rotation_completed_create(uint64_t id,
407 struct lttng_trace_archive_location *location)
408 {
409 return lttng_evaluation_session_rotation_create(
410 LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED, id, location);
411 }
412
413 enum lttng_condition_status
414 lttng_condition_session_rotation_get_session_name(const struct lttng_condition *condition,
415 const char **session_name)
416 {
417 struct lttng_condition_session_rotation *rotation;
418 enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
419
420 if (!condition || !is_rotation_condition(condition) || !session_name) {
421 status = LTTNG_CONDITION_STATUS_INVALID;
422 goto end;
423 }
424
425 rotation = lttng::utils::container_of(condition, &lttng_condition_session_rotation::parent);
426 if (!rotation->session_name) {
427 status = LTTNG_CONDITION_STATUS_UNSET;
428 goto end;
429 }
430 *session_name = rotation->session_name;
431 end:
432 return status;
433 }
434
435 enum lttng_condition_status
436 lttng_condition_session_rotation_set_session_name(struct lttng_condition *condition,
437 const char *session_name)
438 {
439 char *session_name_copy;
440 struct lttng_condition_session_rotation *rotation;
441 enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
442
443 if (!condition || !is_rotation_condition(condition) || !session_name ||
444 strlen(session_name) == 0) {
445 status = LTTNG_CONDITION_STATUS_INVALID;
446 goto end;
447 }
448
449 rotation = lttng::utils::container_of(condition, &lttng_condition_session_rotation::parent);
450 session_name_copy = strdup(session_name);
451 if (!session_name_copy) {
452 status = LTTNG_CONDITION_STATUS_ERROR;
453 goto end;
454 }
455
456 free(rotation->session_name);
457 rotation->session_name = session_name_copy;
458 end:
459 return status;
460 }
461
462 static int lttng_evaluation_session_rotation_serialize(const struct lttng_evaluation *evaluation,
463 struct lttng_payload *payload)
464 {
465 int ret;
466 struct lttng_evaluation_session_rotation *rotation;
467 struct lttng_evaluation_session_rotation_comm comm = {};
468
469 rotation =
470 lttng::utils::container_of(evaluation, &lttng_evaluation_session_rotation::parent);
471 comm.id = rotation->id;
472 comm.has_location = !!rotation->location;
473 ret = lttng_dynamic_buffer_append(&payload->buffer, &comm, sizeof(comm));
474 if (ret) {
475 goto end;
476 }
477 if (!rotation->location) {
478 goto end;
479 }
480 ret = lttng_trace_archive_location_serialize(rotation->location, &payload->buffer);
481 end:
482 return ret;
483 }
484
485 static void lttng_evaluation_session_rotation_destroy(struct lttng_evaluation *evaluation)
486 {
487 struct lttng_evaluation_session_rotation *rotation;
488
489 rotation =
490 lttng::utils::container_of(evaluation, &lttng_evaluation_session_rotation::parent);
491 lttng_trace_archive_location_put(rotation->location);
492 free(rotation);
493 }
494
495 enum lttng_evaluation_status
496 lttng_evaluation_session_rotation_get_id(const struct lttng_evaluation *evaluation, uint64_t *id)
497 {
498 const struct lttng_evaluation_session_rotation *rotation;
499 enum lttng_evaluation_status status = LTTNG_EVALUATION_STATUS_OK;
500
501 if (!evaluation || !id || !is_rotation_evaluation(evaluation)) {
502 status = LTTNG_EVALUATION_STATUS_INVALID;
503 goto end;
504 }
505
506 rotation =
507 lttng::utils::container_of(evaluation, &lttng_evaluation_session_rotation::parent);
508 *id = rotation->id;
509 end:
510 return status;
511 }
512
513 /*
514 * The public API assumes that trace archive locations are always provided as
515 * "constant". This means that the user of liblttng-ctl never has to destroy a
516 * trace archive location. Hence, users of liblttng-ctl have no visibility of
517 * the reference counting of archive locations.
518 */
519 enum lttng_evaluation_status lttng_evaluation_session_rotation_completed_get_location(
520 const struct lttng_evaluation *evaluation,
521 const struct lttng_trace_archive_location **location)
522 {
523 const struct lttng_evaluation_session_rotation *rotation;
524 enum lttng_evaluation_status status = LTTNG_EVALUATION_STATUS_OK;
525
526 if (!evaluation || !location ||
527 evaluation->type != LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED) {
528 status = LTTNG_EVALUATION_STATUS_INVALID;
529 goto end;
530 }
531
532 rotation =
533 lttng::utils::container_of(evaluation, &lttng_evaluation_session_rotation::parent);
534 *location = rotation->location;
535 end:
536 return status;
537 }
538
539 static enum lttng_error_code
540 lttng_condition_session_rotation_mi_serialize(const struct lttng_condition *condition,
541 struct mi_writer *writer)
542 {
543 int ret;
544 enum lttng_error_code ret_code;
545 enum lttng_condition_status status;
546 const char *session_name = nullptr;
547 const char *type_element_str = nullptr;
548
549 LTTNG_ASSERT(condition);
550 LTTNG_ASSERT(writer);
551 LTTNG_ASSERT(is_rotation_condition(condition));
552
553 switch (lttng_condition_get_type(condition)) {
554 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
555 type_element_str = mi_lttng_element_condition_session_rotation_completed;
556 break;
557 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
558 type_element_str = mi_lttng_element_condition_session_rotation_ongoing;
559 break;
560 default:
561 abort();
562 break;
563 }
564
565 status = lttng_condition_session_rotation_get_session_name(condition, &session_name);
566 LTTNG_ASSERT(status == LTTNG_CONDITION_STATUS_OK);
567 LTTNG_ASSERT(session_name);
568
569 /* Open condition session rotation_* element. */
570 ret = mi_lttng_writer_open_element(writer, type_element_str);
571 if (ret) {
572 goto mi_error;
573 }
574
575 /* Session name. */
576 ret = mi_lttng_writer_write_element_string(
577 writer, mi_lttng_element_session_name, session_name);
578 if (ret) {
579 goto mi_error;
580 }
581
582 /* Close condition session rotation element. */
583 ret = mi_lttng_writer_close_element(writer);
584 if (ret) {
585 goto mi_error;
586 }
587
588 ret_code = LTTNG_OK;
589 goto end;
590
591 mi_error:
592 ret_code = LTTNG_ERR_MI_IO_FAIL;
593 end:
594 return ret_code;
595 }
This page took 0.040832 seconds and 4 git commands to generate.