2 * Copyright (C) 2019 Simon Marchi <simon.marchi@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
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>
15 #include <lttng/action/action-internal.hpp>
16 #include <lttng/action/rate-policy-internal.hpp>
17 #include <lttng/action/rate-policy.h>
18 #include <lttng/action/snapshot-session-internal.hpp>
19 #include <lttng/action/snapshot-session.h>
20 #include <lttng/snapshot-internal.hpp>
21 #include <lttng/snapshot.h>
23 #define IS_SNAPSHOT_SESSION_ACTION(action) \
24 (lttng_action_get_type(action) == LTTNG_ACTION_TYPE_SNAPSHOT_SESSION)
27 struct lttng_action_snapshot_session
{
28 struct lttng_action parent
;
34 * When non-NULL, use this custom output when taking the snapshot,
35 * rather than the session's registered snapshot output.
39 struct lttng_snapshot_output
*output
;
40 struct lttng_rate_policy
*policy
;
43 struct lttng_action_snapshot_session_comm
{
44 /* All string lengths include the trailing \0. */
45 uint32_t session_name_len
;
46 uint32_t snapshot_output_len
;
47 uint32_t rate_policy_len
;
50 * Variable data (all strings are null-terminated):
52 * - session name string
53 * - snapshot output object
60 static const struct lttng_rate_policy
*
61 lttng_action_snapshot_session_internal_get_rate_policy(
62 const struct lttng_action
*action
);
64 static struct lttng_action_snapshot_session
*
65 action_snapshot_session_from_action(struct lttng_action
*action
)
69 return lttng::utils::container_of(
70 action
, <tng_action_snapshot_session::parent
);
73 static const struct lttng_action_snapshot_session
*
74 action_snapshot_session_from_action_const(const struct lttng_action
*action
)
78 return lttng::utils::container_of(
79 action
, <tng_action_snapshot_session::parent
);
82 static bool lttng_action_snapshot_session_validate(struct lttng_action
*action
)
85 struct lttng_action_snapshot_session
*action_snapshot_session
;
91 action_snapshot_session
= action_snapshot_session_from_action(action
);
93 /* A non-empty session name is mandatory. */
94 if (!action_snapshot_session
->session_name
||
95 strlen(action_snapshot_session
->session_name
) == 0) {
99 if (action_snapshot_session
->output
&&
100 !lttng_snapshot_output_validate(action_snapshot_session
->output
)) {
109 static bool lttng_action_snapshot_session_is_equal(
110 const struct lttng_action
*_a
, const struct lttng_action
*_b
)
112 bool is_equal
= false;
113 const struct lttng_action_snapshot_session
*a
, *b
;
115 a
= action_snapshot_session_from_action_const(_a
);
116 b
= action_snapshot_session_from_action_const(_b
);
118 /* Action is not valid if this is not true. */
119 LTTNG_ASSERT(a
->session_name
);
120 LTTNG_ASSERT(b
->session_name
);
121 if (strcmp(a
->session_name
, b
->session_name
)) {
125 if (a
->output
&& b
->output
&&
126 !lttng_snapshot_output_is_equal(a
->output
, b
->output
)) {
128 } else if (!!a
->output
!= !!b
->output
) {
132 is_equal
= lttng_rate_policy_is_equal(a
->policy
, b
->policy
);
137 static size_t serialize_strlen(const char *str
)
139 return str
? strlen(str
) + 1 : 0;
142 static int lttng_action_snapshot_session_serialize(
143 struct lttng_action
*action
, struct lttng_payload
*payload
)
145 struct lttng_action_snapshot_session
*action_snapshot_session
;
146 struct lttng_action_snapshot_session_comm comm
= {};
148 size_t size_before_comm
;
150 LTTNG_ASSERT(action
);
151 LTTNG_ASSERT(payload
);
153 size_before_comm
= payload
->buffer
.size
;
155 action_snapshot_session
= action_snapshot_session_from_action(action
);
156 comm
.session_name_len
=
157 serialize_strlen(action_snapshot_session
->session_name
);
160 ret
= lttng_dynamic_buffer_append(
161 &payload
->buffer
, &comm
, sizeof(comm
));
166 LTTNG_ASSERT(action_snapshot_session
->session_name
);
167 DBG("Serializing snapshot session action: session-name: %s",
168 action_snapshot_session
->session_name
);
170 /* Add session name. */
171 ret
= lttng_dynamic_buffer_append(&payload
->buffer
,
172 action_snapshot_session
->session_name
,
173 comm
.session_name_len
);
178 /* Serialize the snapshot output object, if any. */
179 if (action_snapshot_session
->output
) {
180 const size_t size_before_output
= payload
->buffer
.size
;
181 struct lttng_action_snapshot_session_comm
*comm_in_payload
;
183 ret
= lttng_snapshot_output_serialize(
184 action_snapshot_session
->output
,
190 comm_in_payload
= (typeof(comm_in_payload
))(
191 payload
->buffer
.data
+ size_before_comm
);
192 /* Adjust action length in header. */
193 comm_in_payload
->snapshot_output_len
=
194 payload
->buffer
.size
- size_before_output
;
197 /* Serialize the rate policy. */
199 const size_t size_before_output
= payload
->buffer
.size
;
200 struct lttng_action_snapshot_session_comm
*comm_in_payload
;
202 ret
= lttng_rate_policy_serialize(
203 action_snapshot_session
->policy
, payload
);
209 comm_in_payload
= (typeof(comm_in_payload
))(
210 payload
->buffer
.data
+ size_before_comm
);
211 /* Adjust rate policy length in header. */
212 comm_in_payload
->rate_policy_len
=
213 payload
->buffer
.size
- size_before_output
;
220 static void lttng_action_snapshot_session_destroy(struct lttng_action
*action
)
222 struct lttng_action_snapshot_session
*action_snapshot_session
;
228 action_snapshot_session
= action_snapshot_session_from_action(action
);
230 free(action_snapshot_session
->session_name
);
231 lttng_snapshot_output_destroy(action_snapshot_session
->output
);
232 lttng_rate_policy_destroy(action_snapshot_session
->policy
);
233 free(action_snapshot_session
);
239 ssize_t
lttng_action_snapshot_session_create_from_payload(
240 struct lttng_payload_view
*view
,
241 struct lttng_action
**p_action
)
243 ssize_t consumed_len
;
244 const char *variable_data
;
245 struct lttng_action
*action
;
246 enum lttng_action_status status
;
247 struct lttng_snapshot_output
*snapshot_output
= NULL
;
248 struct lttng_rate_policy
*policy
= NULL
;
249 const struct lttng_action_snapshot_session_comm
*comm
;
250 const struct lttng_payload_view snapshot_session_comm_view
=
251 lttng_payload_view_from_view(
252 view
, 0, sizeof(*comm
));
254 action
= lttng_action_snapshot_session_create();
259 if (!lttng_payload_view_is_valid(&snapshot_session_comm_view
)) {
260 /* Payload not large enough to contain the header. */
264 comm
= (typeof(comm
)) snapshot_session_comm_view
.buffer
.data
;
265 variable_data
= (const char *) &comm
->data
;
267 consumed_len
= sizeof(struct lttng_action_snapshot_session_comm
);
269 if (!lttng_buffer_view_contains_string(
270 &view
->buffer
, variable_data
, comm
->session_name_len
)) {
274 status
= lttng_action_snapshot_session_set_session_name(
275 action
, variable_data
);
276 if (status
!= LTTNG_ACTION_STATUS_OK
) {
280 variable_data
+= comm
->session_name_len
;
281 consumed_len
+= comm
->session_name_len
;
283 /* If there is a snapshot output object, deserialize it. */
284 if (comm
->snapshot_output_len
> 0) {
285 ssize_t snapshot_output_consumed_len
;
286 enum lttng_action_status action_status
;
287 struct lttng_payload_view snapshot_output_buffer_view
=
288 lttng_payload_view_from_view(view
, consumed_len
,
289 comm
->snapshot_output_len
);
291 if (!lttng_payload_view_is_valid(&snapshot_output_buffer_view
)) {
292 ERR("Failed to create buffer view for snapshot output.");
296 snapshot_output_consumed_len
=
297 lttng_snapshot_output_create_from_payload(
298 &snapshot_output_buffer_view
,
300 if (snapshot_output_consumed_len
!= comm
->snapshot_output_len
) {
301 ERR("Failed to deserialize snapshot output object: "
302 "consumed-len: %zd, expected-len: %" PRIu32
,
303 snapshot_output_consumed_len
,
304 comm
->snapshot_output_len
);
308 action_status
= lttng_action_snapshot_session_set_output(
309 action
, snapshot_output
);
310 if (action_status
!= LTTNG_ACTION_STATUS_OK
) {
314 /* Ownership has been transferred to the action. */
315 snapshot_output
= NULL
;
318 variable_data
+= comm
->snapshot_output_len
;
319 consumed_len
+= comm
->snapshot_output_len
;
322 if (comm
->rate_policy_len
<= 0) {
323 ERR("Rate policy should be present.");
327 ssize_t rate_policy_consumed_len
;
328 struct lttng_payload_view policy_view
=
329 lttng_payload_view_from_view(view
, consumed_len
,
330 comm
->rate_policy_len
);
332 if (!lttng_payload_view_is_valid(&policy_view
)) {
333 ERR("Failed to create buffer view for rate policy.");
337 rate_policy_consumed_len
=
338 lttng_rate_policy_create_from_payload(
339 &policy_view
, &policy
);
340 if (rate_policy_consumed_len
< 0) {
344 if (rate_policy_consumed_len
!= comm
->rate_policy_len
) {
345 ERR("Failed to deserialize rate policy object: "
346 "consumed-len: %zd, expected-len: %" PRIu32
,
347 rate_policy_consumed_len
,
348 comm
->rate_policy_len
);
352 status
= lttng_action_snapshot_session_set_rate_policy(
354 if (status
!= LTTNG_ACTION_STATUS_OK
) {
359 variable_data
+= comm
->rate_policy_len
;
360 consumed_len
+= comm
->rate_policy_len
;
371 lttng_rate_policy_destroy(policy
);
372 lttng_action_snapshot_session_destroy(action
);
373 lttng_snapshot_output_destroy(snapshot_output
);
378 static enum lttng_error_code
lttng_action_snapshot_session_mi_serialize(
379 const struct lttng_action
*action
, struct mi_writer
*writer
)
382 enum lttng_error_code ret_code
;
383 enum lttng_action_status status
;
384 const char *session_name
= NULL
;
385 const struct lttng_snapshot_output
*output
= NULL
;
386 const struct lttng_rate_policy
*policy
= NULL
;
388 LTTNG_ASSERT(action
);
389 LTTNG_ASSERT(IS_SNAPSHOT_SESSION_ACTION(action
));
391 status
= lttng_action_snapshot_session_get_session_name(
392 action
, &session_name
);
393 LTTNG_ASSERT(status
== LTTNG_ACTION_STATUS_OK
);
394 LTTNG_ASSERT(session_name
!= NULL
);
396 status
= lttng_action_snapshot_session_get_rate_policy(action
, &policy
);
397 LTTNG_ASSERT(status
== LTTNG_ACTION_STATUS_OK
);
398 LTTNG_ASSERT(policy
!= NULL
);
400 /* Open action snapshot session element. */
401 ret
= mi_lttng_writer_open_element(
402 writer
, mi_lttng_element_action_snapshot_session
);
408 ret
= mi_lttng_writer_write_element_string(
409 writer
, mi_lttng_element_session_name
, session_name
);
415 status
= lttng_action_snapshot_session_get_output(action
, &output
);
416 if (status
== LTTNG_ACTION_STATUS_OK
) {
417 LTTNG_ASSERT(output
!= NULL
);
418 ret_code
= lttng_snapshot_output_mi_serialize(output
, writer
);
419 if (ret_code
!= LTTNG_OK
) {
422 } else if (status
!= LTTNG_ACTION_STATUS_UNSET
) {
423 /* This should not happen at this point. */
428 ret_code
= lttng_rate_policy_mi_serialize(policy
, writer
);
429 if (ret_code
!= LTTNG_OK
) {
433 /* Close action_snapshot_session element. */
434 ret
= mi_lttng_writer_close_element(writer
);
443 ret_code
= LTTNG_ERR_MI_IO_FAIL
;
448 struct lttng_action
*lttng_action_snapshot_session_create(void)
450 struct lttng_action_snapshot_session
*action_snapshot
= NULL
;
451 struct lttng_rate_policy
*policy
= NULL
;
452 enum lttng_action_status status
;
454 /* Create a every N = 1 rate policy. */
455 policy
= lttng_rate_policy_every_n_create(1);
460 action_snapshot
= zmalloc
<lttng_action_snapshot_session
>();
461 if (!action_snapshot
) {
465 lttng_action_init(&action_snapshot
->parent
,
466 LTTNG_ACTION_TYPE_SNAPSHOT_SESSION
,
467 lttng_action_snapshot_session_validate
,
468 lttng_action_snapshot_session_serialize
,
469 lttng_action_snapshot_session_is_equal
,
470 lttng_action_snapshot_session_destroy
,
471 lttng_action_snapshot_session_internal_get_rate_policy
,
472 lttng_action_generic_add_error_query_results
,
473 lttng_action_snapshot_session_mi_serialize
);
475 status
= lttng_action_snapshot_session_set_rate_policy(
476 &action_snapshot
->parent
, policy
);
477 if (status
!= LTTNG_ACTION_STATUS_OK
) {
478 lttng_action_destroy(&action_snapshot
->parent
);
479 action_snapshot
= NULL
;
484 lttng_rate_policy_destroy(policy
);
485 return action_snapshot
? &action_snapshot
->parent
: nullptr;
488 enum lttng_action_status
lttng_action_snapshot_session_set_session_name(
489 struct lttng_action
*action
, const char *session_name
)
491 struct lttng_action_snapshot_session
*action_snapshot_session
;
492 enum lttng_action_status status
;
494 if (!action
|| !IS_SNAPSHOT_SESSION_ACTION(action
) || !session_name
||
495 strlen(session_name
) == 0) {
496 status
= LTTNG_ACTION_STATUS_INVALID
;
500 action_snapshot_session
= action_snapshot_session_from_action(action
);
502 free(action_snapshot_session
->session_name
);
504 action_snapshot_session
->session_name
= strdup(session_name
);
505 if (!action_snapshot_session
->session_name
) {
506 status
= LTTNG_ACTION_STATUS_ERROR
;
510 status
= LTTNG_ACTION_STATUS_OK
;
515 enum lttng_action_status
lttng_action_snapshot_session_get_session_name(
516 const struct lttng_action
*action
, const char **session_name
)
518 const struct lttng_action_snapshot_session
*action_snapshot_session
;
519 enum lttng_action_status status
;
521 if (!action
|| !IS_SNAPSHOT_SESSION_ACTION(action
) || !session_name
) {
522 status
= LTTNG_ACTION_STATUS_INVALID
;
526 action_snapshot_session
= action_snapshot_session_from_action_const(action
);
528 if (action_snapshot_session
->session_name
) {
529 *session_name
= action_snapshot_session
->session_name
;
530 status
= LTTNG_ACTION_STATUS_OK
;
532 status
= LTTNG_ACTION_STATUS_UNSET
;
540 enum lttng_action_status
lttng_action_snapshot_session_set_output(
541 struct lttng_action
*action
,
542 struct lttng_snapshot_output
*output
)
544 struct lttng_action_snapshot_session
*action_snapshot_session
;
545 enum lttng_action_status status
;
547 if (!action
|| !IS_SNAPSHOT_SESSION_ACTION(action
) || !output
) {
548 status
= LTTNG_ACTION_STATUS_INVALID
;
552 action_snapshot_session
= action_snapshot_session_from_action(action
);
554 lttng_snapshot_output_destroy(action_snapshot_session
->output
);
555 action_snapshot_session
->output
= output
;
557 status
= LTTNG_ACTION_STATUS_OK
;
563 enum lttng_action_status
lttng_action_snapshot_session_get_output(
564 const struct lttng_action
*action
,
565 const struct lttng_snapshot_output
**output
)
567 const struct lttng_action_snapshot_session
*action_snapshot_session
;
568 enum lttng_action_status status
;
570 if (!action
|| !IS_SNAPSHOT_SESSION_ACTION(action
)|| !output
) {
571 status
= LTTNG_ACTION_STATUS_INVALID
;
575 action_snapshot_session
= action_snapshot_session_from_action_const(action
);
577 if (action_snapshot_session
->output
) {
578 *output
= action_snapshot_session
->output
;
579 status
= LTTNG_ACTION_STATUS_OK
;
581 status
= LTTNG_ACTION_STATUS_UNSET
;
588 enum lttng_action_status
lttng_action_snapshot_session_set_rate_policy(
589 struct lttng_action
*action
,
590 const struct lttng_rate_policy
*policy
)
592 enum lttng_action_status status
;
593 struct lttng_action_snapshot_session
*snapshot_session_action
;
594 struct lttng_rate_policy
*copy
= NULL
;
596 if (!action
|| !policy
|| !IS_SNAPSHOT_SESSION_ACTION(action
)) {
597 status
= LTTNG_ACTION_STATUS_INVALID
;
601 copy
= lttng_rate_policy_copy(policy
);
603 status
= LTTNG_ACTION_STATUS_ERROR
;
607 snapshot_session_action
= action_snapshot_session_from_action(action
);
609 /* Free the previous rate policy .*/
610 lttng_rate_policy_destroy(snapshot_session_action
->policy
);
612 /* Assign the policy. */
613 snapshot_session_action
->policy
= copy
;
614 status
= LTTNG_ACTION_STATUS_OK
;
618 lttng_rate_policy_destroy(copy
);
622 enum lttng_action_status
lttng_action_snapshot_session_get_rate_policy(
623 const struct lttng_action
*action
,
624 const struct lttng_rate_policy
**policy
)
626 enum lttng_action_status status
;
627 const struct lttng_action_snapshot_session
*snapshot_session_action
;
629 if (!action
|| !policy
|| !IS_SNAPSHOT_SESSION_ACTION(action
)) {
630 status
= LTTNG_ACTION_STATUS_INVALID
;
634 snapshot_session_action
=
635 action_snapshot_session_from_action_const(action
);
637 *policy
= snapshot_session_action
->policy
;
638 status
= LTTNG_ACTION_STATUS_OK
;
643 static const struct lttng_rate_policy
*
644 lttng_action_snapshot_session_internal_get_rate_policy(
645 const struct lttng_action
*action
)
647 const struct lttng_action_snapshot_session
*_action
;
648 _action
= action_snapshot_session_from_action_const(action
);
650 return _action
->policy
;