Fix: liblttng-ctl: non-packed structure used for tracker serialization
[lttng-tools.git] / src / common / actions / snapshot-session.cpp
CommitLineData
757c48a2
SM
1/*
2 * Copyright (C) 2019 Simon Marchi <simon.marchi@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
c9e313bc
SM
8#include <common/error.hpp>
9#include <common/macros.hpp>
10#include <common/mi-lttng.hpp>
11#include <common/payload-view.hpp>
12#include <common/payload.hpp>
13#include <common/snapshot.hpp>
d35c7a38 14#include <inttypes.h>
c9e313bc
SM
15#include <lttng/action/action-internal.hpp>
16#include <lttng/action/rate-policy-internal.hpp>
7f4d5b07 17#include <lttng/action/rate-policy.h>
c9e313bc 18#include <lttng/action/snapshot-session-internal.hpp>
757c48a2 19#include <lttng/action/snapshot-session.h>
c9e313bc 20#include <lttng/snapshot-internal.hpp>
d35c7a38 21#include <lttng/snapshot.h>
757c48a2
SM
22
23#define IS_SNAPSHOT_SESSION_ACTION(action) \
17182cfd 24 (lttng_action_get_type(action) == LTTNG_ACTION_TYPE_SNAPSHOT_SESSION)
757c48a2
SM
25
26struct lttng_action_snapshot_session {
27 struct lttng_action parent;
28
29 /* Owned by this. */
30 char *session_name;
31
32 /*
33 * When non-NULL, use this custom output when taking the snapshot,
34 * rather than the session's registered snapshot output.
35 *
36 * Owned by this.
37 */
38 struct lttng_snapshot_output *output;
7f4d5b07 39 struct lttng_rate_policy *policy;
757c48a2
SM
40};
41
42struct lttng_action_snapshot_session_comm {
43 /* All string lengths include the trailing \0. */
44 uint32_t session_name_len;
45 uint32_t snapshot_output_len;
7f4d5b07 46 uint32_t rate_policy_len;
757c48a2
SM
47
48 /*
49 * Variable data (all strings are null-terminated):
50 *
51 * - session name string
52 * - snapshot output object
d35c7a38 53 * - policy object
757c48a2
SM
54 */
55 char data[];
56} LTTNG_PACKED;
57
7f4d5b07
JR
58static const struct lttng_rate_policy *
59lttng_action_snapshot_session_internal_get_rate_policy(
2d57482c
JR
60 const struct lttng_action *action);
61
757c48a2
SM
62static struct lttng_action_snapshot_session *
63action_snapshot_session_from_action(struct lttng_action *action)
64{
a0377dfe 65 LTTNG_ASSERT(action);
757c48a2
SM
66
67 return container_of(
68 action, struct lttng_action_snapshot_session, parent);
69}
70
71static const struct lttng_action_snapshot_session *
72action_snapshot_session_from_action_const(const struct lttng_action *action)
73{
a0377dfe 74 LTTNG_ASSERT(action);
757c48a2
SM
75
76 return container_of(
77 action, struct lttng_action_snapshot_session, parent);
78}
79
80static bool lttng_action_snapshot_session_validate(struct lttng_action *action)
81{
82 bool valid = false;
83 struct lttng_action_snapshot_session *action_snapshot_session;
84
85 if (!action) {
86 goto end;
87 }
88
89 action_snapshot_session = action_snapshot_session_from_action(action);
90
91 /* A non-empty session name is mandatory. */
92 if (!action_snapshot_session->session_name ||
93 strlen(action_snapshot_session->session_name) == 0) {
94 goto end;
95 }
96
97 if (action_snapshot_session->output &&
98 !lttng_snapshot_output_validate(action_snapshot_session->output)) {
99 goto end;
100 }
101
102 valid = true;
103end:
104 return valid;
105}
106
107static bool lttng_action_snapshot_session_is_equal(
108 const struct lttng_action *_a, const struct lttng_action *_b)
109{
110 bool is_equal = false;
111 const struct lttng_action_snapshot_session *a, *b;
112
113 a = action_snapshot_session_from_action_const(_a);
114 b = action_snapshot_session_from_action_const(_b);
115
116 /* Action is not valid if this is not true. */
a0377dfe
FD
117 LTTNG_ASSERT(a->session_name);
118 LTTNG_ASSERT(b->session_name);
757c48a2
SM
119 if (strcmp(a->session_name, b->session_name)) {
120 goto end;
121 }
122
123 if (a->output && b->output &&
124 !lttng_snapshot_output_is_equal(a->output, b->output)) {
125 goto end;
126 } else if (!!a->output != !!b->output) {
127 goto end;
128 }
129
7f4d5b07 130 is_equal = lttng_rate_policy_is_equal(a->policy, b->policy);
757c48a2
SM
131end:
132 return is_equal;
133}
134
0c51e8f3 135static size_t serialize_strlen(const char *str)
757c48a2 136{
0c51e8f3 137 return str ? strlen(str) + 1 : 0;
757c48a2
SM
138}
139
140static int lttng_action_snapshot_session_serialize(
141 struct lttng_action *action, struct lttng_payload *payload)
142{
143 struct lttng_action_snapshot_session *action_snapshot_session;
144 struct lttng_action_snapshot_session_comm comm = {};
145 int ret;
146 size_t size_before_comm;
147
a0377dfe
FD
148 LTTNG_ASSERT(action);
149 LTTNG_ASSERT(payload);
757c48a2
SM
150
151 size_before_comm = payload->buffer.size;
757c48a2
SM
152
153 action_snapshot_session = action_snapshot_session_from_action(action);
154 comm.session_name_len =
155 serialize_strlen(action_snapshot_session->session_name);
156
157 /* Add header. */
158 ret = lttng_dynamic_buffer_append(
159 &payload->buffer, &comm, sizeof(comm));
160 if (ret) {
161 goto end;
162 }
163
a0377dfe 164 LTTNG_ASSERT(action_snapshot_session->session_name);
757c48a2
SM
165 DBG("Serializing snapshot session action: session-name: %s",
166 action_snapshot_session->session_name);
167
168 /* Add session name. */
169 ret = lttng_dynamic_buffer_append(&payload->buffer,
170 action_snapshot_session->session_name,
171 comm.session_name_len);
172 if (ret) {
173 goto end;
174 }
175
176 /* Serialize the snapshot output object, if any. */
177 if (action_snapshot_session->output) {
178 const size_t size_before_output = payload->buffer.size;
179 struct lttng_action_snapshot_session_comm *comm_in_payload;
180
181 ret = lttng_snapshot_output_serialize(
182 action_snapshot_session->output,
183 payload);
184 if (ret) {
185 goto end;
186 }
187
757c48a2
SM
188 comm_in_payload = (typeof(comm_in_payload))(
189 payload->buffer.data + size_before_comm);
d35c7a38 190 /* Adjust action length in header. */
757c48a2
SM
191 comm_in_payload->snapshot_output_len =
192 payload->buffer.size - size_before_output;
193 }
194
7f4d5b07 195 /* Serialize the rate policy. */
d35c7a38
JR
196 {
197 const size_t size_before_output = payload->buffer.size;
198 struct lttng_action_snapshot_session_comm *comm_in_payload;
199
7f4d5b07 200 ret = lttng_rate_policy_serialize(
d35c7a38
JR
201 action_snapshot_session->policy, payload);
202 if (ret) {
203 ret = -1;
204 goto end;
205 }
206
207 comm_in_payload = (typeof(comm_in_payload))(
208 payload->buffer.data + size_before_comm);
7f4d5b07
JR
209 /* Adjust rate policy length in header. */
210 comm_in_payload->rate_policy_len =
d35c7a38
JR
211 payload->buffer.size - size_before_output;
212 }
213
757c48a2
SM
214end:
215 return ret;
216}
217
218static void lttng_action_snapshot_session_destroy(struct lttng_action *action)
219{
220 struct lttng_action_snapshot_session *action_snapshot_session;
221
222 if (!action) {
223 goto end;
224 }
225
226 action_snapshot_session = action_snapshot_session_from_action(action);
227
228 free(action_snapshot_session->session_name);
229 lttng_snapshot_output_destroy(action_snapshot_session->output);
7f4d5b07 230 lttng_rate_policy_destroy(action_snapshot_session->policy);
757c48a2
SM
231 free(action_snapshot_session);
232
233end:
234 return;
235}
236
237ssize_t lttng_action_snapshot_session_create_from_payload(
238 struct lttng_payload_view *view,
239 struct lttng_action **p_action)
240{
241 ssize_t consumed_len;
757c48a2
SM
242 const char *variable_data;
243 struct lttng_action *action;
244 enum lttng_action_status status;
245 struct lttng_snapshot_output *snapshot_output = NULL;
7f4d5b07 246 struct lttng_rate_policy *policy = NULL;
3e6e0df2
JG
247 const struct lttng_action_snapshot_session_comm *comm;
248 const struct lttng_payload_view snapshot_session_comm_view =
249 lttng_payload_view_from_view(
250 view, 0, sizeof(*comm));
757c48a2
SM
251
252 action = lttng_action_snapshot_session_create();
253 if (!action) {
254 goto error;
255 }
256
3e6e0df2
JG
257 if (!lttng_payload_view_is_valid(&snapshot_session_comm_view)) {
258 /* Payload not large enough to contain the header. */
259 goto error;
260 }
261
262 comm = (typeof(comm)) snapshot_session_comm_view.buffer.data;
757c48a2
SM
263 variable_data = (const char *) &comm->data;
264
265 consumed_len = sizeof(struct lttng_action_snapshot_session_comm);
266
267 if (!lttng_buffer_view_contains_string(
268 &view->buffer, variable_data, comm->session_name_len)) {
269 goto error;
270 }
271
272 status = lttng_action_snapshot_session_set_session_name(
273 action, variable_data);
274 if (status != LTTNG_ACTION_STATUS_OK) {
275 goto error;
276 }
277
278 variable_data += comm->session_name_len;
279 consumed_len += comm->session_name_len;
280
281 /* If there is a snapshot output object, deserialize it. */
282 if (comm->snapshot_output_len > 0) {
283 ssize_t snapshot_output_consumed_len;
284 enum lttng_action_status action_status;
285 struct lttng_payload_view snapshot_output_buffer_view =
286 lttng_payload_view_from_view(view, consumed_len,
287 comm->snapshot_output_len);
288
3e6e0df2 289 if (!lttng_payload_view_is_valid(&snapshot_output_buffer_view)) {
0c51e8f3 290 ERR("Failed to create buffer view for snapshot output.");
757c48a2
SM
291 goto error;
292 }
293
294 snapshot_output_consumed_len =
295 lttng_snapshot_output_create_from_payload(
296 &snapshot_output_buffer_view,
297 &snapshot_output);
298 if (snapshot_output_consumed_len != comm->snapshot_output_len) {
0c51e8f3 299 ERR("Failed to deserialize snapshot output object: "
757c48a2
SM
300 "consumed-len: %zd, expected-len: %" PRIu32,
301 snapshot_output_consumed_len,
302 comm->snapshot_output_len);
303 goto error;
304 }
305
306 action_status = lttng_action_snapshot_session_set_output(
307 action, snapshot_output);
308 if (action_status != LTTNG_ACTION_STATUS_OK) {
309 goto error;
310 }
311
312 /* Ownership has been transferred to the action. */
313 snapshot_output = NULL;
314 }
315
316 variable_data += comm->snapshot_output_len;
317 consumed_len += comm->snapshot_output_len;
d35c7a38 318
7f4d5b07
JR
319 /* Rate policy. */
320 if (comm->rate_policy_len <= 0) {
321 ERR("Rate policy should be present.");
d35c7a38
JR
322 goto error;
323 }
324 {
7f4d5b07 325 ssize_t rate_policy_consumed_len;
d35c7a38
JR
326 struct lttng_payload_view policy_view =
327 lttng_payload_view_from_view(view, consumed_len,
7f4d5b07 328 comm->rate_policy_len);
d35c7a38
JR
329
330 if (!lttng_payload_view_is_valid(&policy_view)) {
7f4d5b07 331 ERR("Failed to create buffer view for rate policy.");
d35c7a38
JR
332 goto error;
333 }
334
7f4d5b07
JR
335 rate_policy_consumed_len =
336 lttng_rate_policy_create_from_payload(
d35c7a38 337 &policy_view, &policy);
7f4d5b07 338 if (rate_policy_consumed_len < 0) {
d35c7a38
JR
339 goto error;
340 }
341
7f4d5b07
JR
342 if (rate_policy_consumed_len != comm->rate_policy_len) {
343 ERR("Failed to deserialize rate policy object: "
d35c7a38 344 "consumed-len: %zd, expected-len: %" PRIu32,
7f4d5b07
JR
345 rate_policy_consumed_len,
346 comm->rate_policy_len);
d35c7a38
JR
347 goto error;
348 }
349
7f4d5b07 350 status = lttng_action_snapshot_session_set_rate_policy(
d35c7a38
JR
351 action, policy);
352 if (status != LTTNG_ACTION_STATUS_OK) {
353 goto error;
354 }
355 }
356
7f4d5b07
JR
357 variable_data += comm->rate_policy_len;
358 consumed_len += comm->rate_policy_len;
d35c7a38 359
757c48a2
SM
360 *p_action = action;
361 action = NULL;
362
363 goto end;
364
365error:
366 consumed_len = -1;
367
368end:
7f4d5b07 369 lttng_rate_policy_destroy(policy);
757c48a2
SM
370 lttng_action_snapshot_session_destroy(action);
371 lttng_snapshot_output_destroy(snapshot_output);
372
373 return consumed_len;
374}
375
6a751b95
JR
376static enum lttng_error_code lttng_action_snapshot_session_mi_serialize(
377 const struct lttng_action *action, struct mi_writer *writer)
378{
379 int ret;
380 enum lttng_error_code ret_code;
381 enum lttng_action_status status;
382 const char *session_name = NULL;
383 const struct lttng_snapshot_output *output = NULL;
384 const struct lttng_rate_policy *policy = NULL;
385
a0377dfe
FD
386 LTTNG_ASSERT(action);
387 LTTNG_ASSERT(IS_SNAPSHOT_SESSION_ACTION(action));
6a751b95
JR
388
389 status = lttng_action_snapshot_session_get_session_name(
390 action, &session_name);
a0377dfe
FD
391 LTTNG_ASSERT(status == LTTNG_ACTION_STATUS_OK);
392 LTTNG_ASSERT(session_name != NULL);
6a751b95
JR
393
394 status = lttng_action_snapshot_session_get_rate_policy(action, &policy);
a0377dfe
FD
395 LTTNG_ASSERT(status == LTTNG_ACTION_STATUS_OK);
396 LTTNG_ASSERT(policy != NULL);
6a751b95
JR
397
398 /* Open action snapshot session element. */
399 ret = mi_lttng_writer_open_element(
400 writer, mi_lttng_element_action_snapshot_session);
401 if (ret) {
402 goto mi_error;
403 }
404
405 /* Session name. */
406 ret = mi_lttng_writer_write_element_string(
407 writer, mi_lttng_element_session_name, session_name);
408 if (ret) {
409 goto mi_error;
410 }
411
412 /* Output if any. */
413 status = lttng_action_snapshot_session_get_output(action, &output);
414 if (status == LTTNG_ACTION_STATUS_OK) {
a0377dfe 415 LTTNG_ASSERT(output != NULL);
6a751b95
JR
416 ret_code = lttng_snapshot_output_mi_serialize(output, writer);
417 if (ret_code != LTTNG_OK) {
418 goto end;
419 }
420 } else if (status != LTTNG_ACTION_STATUS_UNSET) {
421 /* This should not happen at this point. */
422 abort();
423 }
424
425 /* Rate policy. */
426 ret_code = lttng_rate_policy_mi_serialize(policy, writer);
427 if (ret_code != LTTNG_OK) {
428 goto end;
429 }
430
431 /* Close action_snapshot_session element. */
432 ret = mi_lttng_writer_close_element(writer);
433 if (ret) {
434 goto mi_error;
435 }
436
437 ret_code = LTTNG_OK;
438 goto end;
439
440mi_error:
441 ret_code = LTTNG_ERR_MI_IO_FAIL;
442end:
443 return ret_code;
444}
445
757c48a2
SM
446struct lttng_action *lttng_action_snapshot_session_create(void)
447{
64803277 448 struct lttng_action_snapshot_session *action_snapshot = NULL;
7f4d5b07 449 struct lttng_rate_policy *policy = NULL;
d35c7a38
JR
450 enum lttng_action_status status;
451
7f4d5b07
JR
452 /* Create a every N = 1 rate policy. */
453 policy = lttng_rate_policy_every_n_create(1);
d35c7a38
JR
454 if (!policy) {
455 goto end;
456 }
757c48a2 457
64803277
SM
458 action_snapshot = zmalloc<lttng_action_snapshot_session>();
459 if (!action_snapshot) {
757c48a2
SM
460 goto end;
461 }
462
64803277
SM
463 lttng_action_init(&action_snapshot->parent,
464 LTTNG_ACTION_TYPE_SNAPSHOT_SESSION,
757c48a2
SM
465 lttng_action_snapshot_session_validate,
466 lttng_action_snapshot_session_serialize,
467 lttng_action_snapshot_session_is_equal,
2d57482c 468 lttng_action_snapshot_session_destroy,
588c4b0d 469 lttng_action_snapshot_session_internal_get_rate_policy,
6a751b95
JR
470 lttng_action_generic_add_error_query_results,
471 lttng_action_snapshot_session_mi_serialize);
757c48a2 472
64803277
SM
473 status = lttng_action_snapshot_session_set_rate_policy(
474 &action_snapshot->parent, policy);
d35c7a38 475 if (status != LTTNG_ACTION_STATUS_OK) {
64803277
SM
476 lttng_action_destroy(&action_snapshot->parent);
477 action_snapshot = NULL;
d35c7a38
JR
478 goto end;
479 }
480
757c48a2 481end:
7f4d5b07 482 lttng_rate_policy_destroy(policy);
64803277 483 return action_snapshot ? &action_snapshot->parent : nullptr;
757c48a2
SM
484}
485
486enum lttng_action_status lttng_action_snapshot_session_set_session_name(
487 struct lttng_action *action, const char *session_name)
488{
489 struct lttng_action_snapshot_session *action_snapshot_session;
490 enum lttng_action_status status;
491
492 if (!action || !IS_SNAPSHOT_SESSION_ACTION(action) || !session_name ||
493 strlen(session_name) == 0) {
494 status = LTTNG_ACTION_STATUS_INVALID;
495 goto end;
496 }
497
498 action_snapshot_session = action_snapshot_session_from_action(action);
499
500 free(action_snapshot_session->session_name);
501
502 action_snapshot_session->session_name = strdup(session_name);
503 if (!action_snapshot_session->session_name) {
504 status = LTTNG_ACTION_STATUS_ERROR;
505 goto end;
506 }
507
508 status = LTTNG_ACTION_STATUS_OK;
509end:
510 return status;
511}
512
513enum lttng_action_status lttng_action_snapshot_session_get_session_name(
514 const struct lttng_action *action, const char **session_name)
515{
516 const struct lttng_action_snapshot_session *action_snapshot_session;
517 enum lttng_action_status status;
518
519 if (!action || !IS_SNAPSHOT_SESSION_ACTION(action) || !session_name) {
520 status = LTTNG_ACTION_STATUS_INVALID;
521 goto end;
522 }
523
524 action_snapshot_session = action_snapshot_session_from_action_const(action);
525
526 if (action_snapshot_session->session_name) {
527 *session_name = action_snapshot_session->session_name;
528 status = LTTNG_ACTION_STATUS_OK;
529 } else {
530 status = LTTNG_ACTION_STATUS_UNSET;
531 }
532
533end:
534
535 return status;
536}
537
538enum lttng_action_status lttng_action_snapshot_session_set_output(
539 struct lttng_action *action,
540 struct lttng_snapshot_output *output)
541{
542 struct lttng_action_snapshot_session *action_snapshot_session;
543 enum lttng_action_status status;
544
545 if (!action || !IS_SNAPSHOT_SESSION_ACTION(action) || !output) {
546 status = LTTNG_ACTION_STATUS_INVALID;
547 goto end;
548 }
549
550 action_snapshot_session = action_snapshot_session_from_action(action);
551
552 lttng_snapshot_output_destroy(action_snapshot_session->output);
553 action_snapshot_session->output = output;
554
555 status = LTTNG_ACTION_STATUS_OK;
556
557end:
558 return status;
559}
560
561enum lttng_action_status lttng_action_snapshot_session_get_output(
562 const struct lttng_action *action,
563 const struct lttng_snapshot_output **output)
564{
565 const struct lttng_action_snapshot_session *action_snapshot_session;
566 enum lttng_action_status status;
567
568 if (!action || !IS_SNAPSHOT_SESSION_ACTION(action)|| !output) {
569 status = LTTNG_ACTION_STATUS_INVALID;
570 goto end;
571 }
572
573 action_snapshot_session = action_snapshot_session_from_action_const(action);
574
575 if (action_snapshot_session->output) {
576 *output = action_snapshot_session->output;
577 status = LTTNG_ACTION_STATUS_OK;
578 } else {
579 status = LTTNG_ACTION_STATUS_UNSET;
580 }
581
582end:
583 return status;
584}
d35c7a38 585
7f4d5b07 586enum lttng_action_status lttng_action_snapshot_session_set_rate_policy(
d35c7a38 587 struct lttng_action *action,
7f4d5b07 588 const struct lttng_rate_policy *policy)
d35c7a38
JR
589{
590 enum lttng_action_status status;
591 struct lttng_action_snapshot_session *snapshot_session_action;
7f4d5b07 592 struct lttng_rate_policy *copy = NULL;
d35c7a38
JR
593
594 if (!action || !policy || !IS_SNAPSHOT_SESSION_ACTION(action)) {
595 status = LTTNG_ACTION_STATUS_INVALID;
596 goto end;
597 }
598
7f4d5b07 599 copy = lttng_rate_policy_copy(policy);
d35c7a38
JR
600 if (!copy) {
601 status = LTTNG_ACTION_STATUS_ERROR;
602 goto end;
603 }
604
605 snapshot_session_action = action_snapshot_session_from_action(action);
606
7f4d5b07
JR
607 /* Free the previous rate policy .*/
608 lttng_rate_policy_destroy(snapshot_session_action->policy);
d35c7a38
JR
609
610 /* Assign the policy. */
611 snapshot_session_action->policy = copy;
612 status = LTTNG_ACTION_STATUS_OK;
613 copy = NULL;
614
615end:
7f4d5b07 616 lttng_rate_policy_destroy(copy);
d35c7a38
JR
617 return status;
618}
619
7f4d5b07 620enum lttng_action_status lttng_action_snapshot_session_get_rate_policy(
d35c7a38 621 const struct lttng_action *action,
7f4d5b07 622 const struct lttng_rate_policy **policy)
d35c7a38
JR
623{
624 enum lttng_action_status status;
625 const struct lttng_action_snapshot_session *snapshot_session_action;
626
627 if (!action || !policy || !IS_SNAPSHOT_SESSION_ACTION(action)) {
628 status = LTTNG_ACTION_STATUS_INVALID;
629 goto end;
630 }
631
632 snapshot_session_action =
633 action_snapshot_session_from_action_const(action);
634
635 *policy = snapshot_session_action->policy;
636 status = LTTNG_ACTION_STATUS_OK;
637end:
638 return status;
639}
2d57482c 640
7f4d5b07
JR
641static const struct lttng_rate_policy *
642lttng_action_snapshot_session_internal_get_rate_policy(
2d57482c
JR
643 const struct lttng_action *action)
644{
645 const struct lttng_action_snapshot_session *_action;
646 _action = action_snapshot_session_from_action_const(action);
647
648 return _action->policy;
649}
This page took 0.068754 seconds and 4 git commands to generate.