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>
25 #define IS_SNAPSHOT_SESSION_ACTION(action) \
26 (lttng_action_get_type(action) == LTTNG_ACTION_TYPE_SNAPSHOT_SESSION)
29 struct lttng_action_snapshot_session
{
30 struct lttng_action parent
;
36 * When non-NULL, use this custom output when taking the snapshot,
37 * rather than the session's registered snapshot output.
41 struct lttng_snapshot_output
*output
;
42 struct lttng_rate_policy
*policy
;
45 struct lttng_action_snapshot_session_comm
{
46 /* All string lengths include the trailing \0. */
47 uint32_t session_name_len
;
48 uint32_t snapshot_output_len
;
49 uint32_t rate_policy_len
;
52 * Variable data (all strings are null-terminated):
54 * - session name string
55 * - snapshot output object
62 static const struct lttng_rate_policy
*
63 lttng_action_snapshot_session_internal_get_rate_policy(const struct lttng_action
*action
);
65 static struct lttng_action_snapshot_session
*
66 action_snapshot_session_from_action(struct lttng_action
*action
)
70 return lttng::utils::container_of(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(action
, <tng_action_snapshot_session::parent
);
81 static bool lttng_action_snapshot_session_validate(struct lttng_action
*action
)
84 struct lttng_action_snapshot_session
*action_snapshot_session
;
90 action_snapshot_session
= action_snapshot_session_from_action(action
);
92 /* A non-empty session name is mandatory. */
93 if (!action_snapshot_session
->session_name
||
94 strlen(action_snapshot_session
->session_name
) == 0) {
98 if (action_snapshot_session
->output
&&
99 !lttng_snapshot_output_validate(action_snapshot_session
->output
)) {
108 static bool lttng_action_snapshot_session_is_equal(const struct lttng_action
*_a
,
109 const struct lttng_action
*_b
)
111 bool is_equal
= false;
112 const struct lttng_action_snapshot_session
*a
, *b
;
114 a
= action_snapshot_session_from_action_const(_a
);
115 b
= action_snapshot_session_from_action_const(_b
);
117 /* Action is not valid if this is not true. */
118 LTTNG_ASSERT(a
->session_name
);
119 LTTNG_ASSERT(b
->session_name
);
120 if (strcmp(a
->session_name
, b
->session_name
) != 0) {
124 if (a
->output
&& b
->output
&& !lttng_snapshot_output_is_equal(a
->output
, b
->output
)) {
126 } else if (!!a
->output
!= !!b
->output
) {
130 is_equal
= lttng_rate_policy_is_equal(a
->policy
, b
->policy
);
135 static size_t serialize_strlen(const char *str
)
137 return str
? strlen(str
) + 1 : 0;
140 static int lttng_action_snapshot_session_serialize(struct lttng_action
*action
,
141 struct lttng_payload
*payload
)
143 struct lttng_action_snapshot_session
*action_snapshot_session
;
144 struct lttng_action_snapshot_session_comm comm
= {};
146 size_t size_before_comm
;
148 LTTNG_ASSERT(action
);
149 LTTNG_ASSERT(payload
);
151 size_before_comm
= payload
->buffer
.size
;
153 action_snapshot_session
= action_snapshot_session_from_action(action
);
154 comm
.session_name_len
= serialize_strlen(action_snapshot_session
->session_name
);
157 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &comm
, sizeof(comm
));
162 LTTNG_ASSERT(action_snapshot_session
->session_name
);
163 DBG("Serializing snapshot session action: session-name: %s",
164 action_snapshot_session
->session_name
);
166 /* Add session name. */
167 ret
= lttng_dynamic_buffer_append(
168 &payload
->buffer
, action_snapshot_session
->session_name
, comm
.session_name_len
);
173 /* Serialize the snapshot output object, if any. */
174 if (action_snapshot_session
->output
) {
175 const size_t size_before_output
= payload
->buffer
.size
;
176 struct lttng_action_snapshot_session_comm
*comm_in_payload
;
178 ret
= lttng_snapshot_output_serialize(action_snapshot_session
->output
, payload
);
184 (typeof(comm_in_payload
)) (payload
->buffer
.data
+ size_before_comm
);
185 /* Adjust action length in header. */
186 comm_in_payload
->snapshot_output_len
= payload
->buffer
.size
- size_before_output
;
189 /* Serialize the rate policy. */
191 const size_t size_before_output
= payload
->buffer
.size
;
192 struct lttng_action_snapshot_session_comm
*comm_in_payload
;
194 ret
= lttng_rate_policy_serialize(action_snapshot_session
->policy
, payload
);
201 (typeof(comm_in_payload
)) (payload
->buffer
.data
+ size_before_comm
);
202 /* Adjust rate policy length in header. */
203 comm_in_payload
->rate_policy_len
= payload
->buffer
.size
- size_before_output
;
210 static void lttng_action_snapshot_session_destroy(struct lttng_action
*action
)
212 struct lttng_action_snapshot_session
*action_snapshot_session
;
218 action_snapshot_session
= action_snapshot_session_from_action(action
);
220 free(action_snapshot_session
->session_name
);
221 lttng_snapshot_output_destroy(action_snapshot_session
->output
);
222 lttng_rate_policy_destroy(action_snapshot_session
->policy
);
223 free(action_snapshot_session
);
229 ssize_t
lttng_action_snapshot_session_create_from_payload(struct lttng_payload_view
*view
,
230 struct lttng_action
**p_action
)
232 ssize_t consumed_len
;
233 const char *variable_data
;
234 struct lttng_action
*action
;
235 enum lttng_action_status status
;
236 struct lttng_snapshot_output
*snapshot_output
= nullptr;
237 struct lttng_rate_policy
*policy
= nullptr;
238 const struct lttng_action_snapshot_session_comm
*comm
;
239 const struct lttng_payload_view snapshot_session_comm_view
=
240 lttng_payload_view_from_view(view
, 0, sizeof(*comm
));
242 action
= lttng_action_snapshot_session_create();
247 if (!lttng_payload_view_is_valid(&snapshot_session_comm_view
)) {
248 /* Payload not large enough to contain the header. */
252 comm
= (typeof(comm
)) snapshot_session_comm_view
.buffer
.data
;
253 variable_data
= (const char *) &comm
->data
;
255 consumed_len
= sizeof(struct lttng_action_snapshot_session_comm
);
257 if (!lttng_buffer_view_contains_string(
258 &view
->buffer
, variable_data
, comm
->session_name_len
)) {
262 status
= lttng_action_snapshot_session_set_session_name(action
, variable_data
);
263 if (status
!= LTTNG_ACTION_STATUS_OK
) {
267 variable_data
+= comm
->session_name_len
;
268 consumed_len
+= comm
->session_name_len
;
270 /* If there is a snapshot output object, deserialize it. */
271 if (comm
->snapshot_output_len
> 0) {
272 ssize_t snapshot_output_consumed_len
;
273 enum lttng_action_status action_status
;
274 struct lttng_payload_view snapshot_output_buffer_view
=
275 lttng_payload_view_from_view(view
, consumed_len
, comm
->snapshot_output_len
);
277 if (!lttng_payload_view_is_valid(&snapshot_output_buffer_view
)) {
278 ERR("Failed to create buffer view for snapshot output.");
282 snapshot_output_consumed_len
= lttng_snapshot_output_create_from_payload(
283 &snapshot_output_buffer_view
, &snapshot_output
);
284 if (snapshot_output_consumed_len
!= comm
->snapshot_output_len
) {
285 ERR("Failed to deserialize snapshot output object: "
286 "consumed-len: %zd, expected-len: %" PRIu32
,
287 snapshot_output_consumed_len
,
288 comm
->snapshot_output_len
);
292 action_status
= lttng_action_snapshot_session_set_output(action
, snapshot_output
);
293 if (action_status
!= LTTNG_ACTION_STATUS_OK
) {
297 /* Ownership has been transferred to the action. */
298 snapshot_output
= nullptr;
301 variable_data
+= comm
->snapshot_output_len
;
302 consumed_len
+= comm
->snapshot_output_len
;
305 if (comm
->rate_policy_len
<= 0) {
306 ERR("Rate policy should be present.");
310 ssize_t rate_policy_consumed_len
;
311 struct lttng_payload_view policy_view
=
312 lttng_payload_view_from_view(view
, consumed_len
, comm
->rate_policy_len
);
314 if (!lttng_payload_view_is_valid(&policy_view
)) {
315 ERR("Failed to create buffer view for rate policy.");
319 rate_policy_consumed_len
=
320 lttng_rate_policy_create_from_payload(&policy_view
, &policy
);
321 if (rate_policy_consumed_len
< 0) {
325 if (rate_policy_consumed_len
!= comm
->rate_policy_len
) {
326 ERR("Failed to deserialize rate policy object: "
327 "consumed-len: %zd, expected-len: %" PRIu32
,
328 rate_policy_consumed_len
,
329 comm
->rate_policy_len
);
333 status
= lttng_action_snapshot_session_set_rate_policy(action
, policy
);
334 if (status
!= LTTNG_ACTION_STATUS_OK
) {
339 variable_data
+= comm
->rate_policy_len
;
340 consumed_len
+= comm
->rate_policy_len
;
351 lttng_rate_policy_destroy(policy
);
352 lttng_action_snapshot_session_destroy(action
);
353 lttng_snapshot_output_destroy(snapshot_output
);
358 static enum lttng_error_code
359 lttng_action_snapshot_session_mi_serialize(const struct lttng_action
*action
,
360 struct mi_writer
*writer
)
363 enum lttng_error_code ret_code
;
364 enum lttng_action_status status
;
365 const char *session_name
= nullptr;
366 const struct lttng_snapshot_output
*output
= nullptr;
367 const struct lttng_rate_policy
*policy
= nullptr;
369 LTTNG_ASSERT(action
);
370 LTTNG_ASSERT(IS_SNAPSHOT_SESSION_ACTION(action
));
372 status
= lttng_action_snapshot_session_get_session_name(action
, &session_name
);
373 LTTNG_ASSERT(status
== LTTNG_ACTION_STATUS_OK
);
374 LTTNG_ASSERT(session_name
!= nullptr);
376 status
= lttng_action_snapshot_session_get_rate_policy(action
, &policy
);
377 LTTNG_ASSERT(status
== LTTNG_ACTION_STATUS_OK
);
378 LTTNG_ASSERT(policy
!= nullptr);
380 /* Open action snapshot session element. */
381 ret
= mi_lttng_writer_open_element(writer
, mi_lttng_element_action_snapshot_session
);
387 ret
= mi_lttng_writer_write_element_string(
388 writer
, mi_lttng_element_session_name
, session_name
);
394 status
= lttng_action_snapshot_session_get_output(action
, &output
);
395 if (status
== LTTNG_ACTION_STATUS_OK
) {
396 LTTNG_ASSERT(output
!= nullptr);
397 ret_code
= lttng_snapshot_output_mi_serialize(output
, writer
);
398 if (ret_code
!= LTTNG_OK
) {
401 } else if (status
!= LTTNG_ACTION_STATUS_UNSET
) {
402 /* This should not happen at this point. */
407 ret_code
= lttng_rate_policy_mi_serialize(policy
, writer
);
408 if (ret_code
!= LTTNG_OK
) {
412 /* Close action_snapshot_session element. */
413 ret
= mi_lttng_writer_close_element(writer
);
422 ret_code
= LTTNG_ERR_MI_IO_FAIL
;
427 struct lttng_action
*lttng_action_snapshot_session_create(void)
429 struct lttng_action_snapshot_session
*action_snapshot
= nullptr;
430 struct lttng_rate_policy
*policy
= nullptr;
431 enum lttng_action_status status
;
433 /* Create a every N = 1 rate policy. */
434 policy
= lttng_rate_policy_every_n_create(1);
439 action_snapshot
= zmalloc
<lttng_action_snapshot_session
>();
440 if (!action_snapshot
) {
444 lttng_action_init(&action_snapshot
->parent
,
445 LTTNG_ACTION_TYPE_SNAPSHOT_SESSION
,
446 lttng_action_snapshot_session_validate
,
447 lttng_action_snapshot_session_serialize
,
448 lttng_action_snapshot_session_is_equal
,
449 lttng_action_snapshot_session_destroy
,
450 lttng_action_snapshot_session_internal_get_rate_policy
,
451 lttng_action_generic_add_error_query_results
,
452 lttng_action_snapshot_session_mi_serialize
);
454 status
= lttng_action_snapshot_session_set_rate_policy(&action_snapshot
->parent
, policy
);
455 if (status
!= LTTNG_ACTION_STATUS_OK
) {
456 lttng_action_destroy(&action_snapshot
->parent
);
457 action_snapshot
= nullptr;
462 lttng_rate_policy_destroy(policy
);
463 return action_snapshot
? &action_snapshot
->parent
: nullptr;
466 enum lttng_action_status
lttng_action_snapshot_session_set_session_name(struct lttng_action
*action
,
467 const char *session_name
)
469 struct lttng_action_snapshot_session
*action_snapshot_session
;
470 enum lttng_action_status status
;
472 if (!action
|| !IS_SNAPSHOT_SESSION_ACTION(action
) || !session_name
||
473 strlen(session_name
) == 0) {
474 status
= LTTNG_ACTION_STATUS_INVALID
;
478 action_snapshot_session
= action_snapshot_session_from_action(action
);
480 free(action_snapshot_session
->session_name
);
482 action_snapshot_session
->session_name
= strdup(session_name
);
483 if (!action_snapshot_session
->session_name
) {
484 status
= LTTNG_ACTION_STATUS_ERROR
;
488 status
= LTTNG_ACTION_STATUS_OK
;
493 enum lttng_action_status
494 lttng_action_snapshot_session_get_session_name(const struct lttng_action
*action
,
495 const char **session_name
)
497 const struct lttng_action_snapshot_session
*action_snapshot_session
;
498 enum lttng_action_status status
;
500 if (!action
|| !IS_SNAPSHOT_SESSION_ACTION(action
) || !session_name
) {
501 status
= LTTNG_ACTION_STATUS_INVALID
;
505 action_snapshot_session
= action_snapshot_session_from_action_const(action
);
507 if (action_snapshot_session
->session_name
) {
508 *session_name
= action_snapshot_session
->session_name
;
509 status
= LTTNG_ACTION_STATUS_OK
;
511 status
= LTTNG_ACTION_STATUS_UNSET
;
519 enum lttng_action_status
520 lttng_action_snapshot_session_set_output(struct lttng_action
*action
,
521 struct lttng_snapshot_output
*output
)
523 struct lttng_action_snapshot_session
*action_snapshot_session
;
524 enum lttng_action_status status
;
526 if (!action
|| !IS_SNAPSHOT_SESSION_ACTION(action
) || !output
) {
527 status
= LTTNG_ACTION_STATUS_INVALID
;
531 action_snapshot_session
= action_snapshot_session_from_action(action
);
533 lttng_snapshot_output_destroy(action_snapshot_session
->output
);
534 action_snapshot_session
->output
= output
;
536 status
= LTTNG_ACTION_STATUS_OK
;
542 enum lttng_action_status
543 lttng_action_snapshot_session_get_output(const struct lttng_action
*action
,
544 const struct lttng_snapshot_output
**output
)
546 const struct lttng_action_snapshot_session
*action_snapshot_session
;
547 enum lttng_action_status status
;
549 if (!action
|| !IS_SNAPSHOT_SESSION_ACTION(action
) || !output
) {
550 status
= LTTNG_ACTION_STATUS_INVALID
;
554 action_snapshot_session
= action_snapshot_session_from_action_const(action
);
556 if (action_snapshot_session
->output
) {
557 *output
= action_snapshot_session
->output
;
558 status
= LTTNG_ACTION_STATUS_OK
;
560 status
= LTTNG_ACTION_STATUS_UNSET
;
567 enum lttng_action_status
568 lttng_action_snapshot_session_set_rate_policy(struct lttng_action
*action
,
569 const struct lttng_rate_policy
*policy
)
571 enum lttng_action_status status
;
572 struct lttng_action_snapshot_session
*snapshot_session_action
;
573 struct lttng_rate_policy
*copy
= nullptr;
575 if (!action
|| !policy
|| !IS_SNAPSHOT_SESSION_ACTION(action
)) {
576 status
= LTTNG_ACTION_STATUS_INVALID
;
580 copy
= lttng_rate_policy_copy(policy
);
582 status
= LTTNG_ACTION_STATUS_ERROR
;
586 snapshot_session_action
= action_snapshot_session_from_action(action
);
588 /* Free the previous rate policy .*/
589 lttng_rate_policy_destroy(snapshot_session_action
->policy
);
591 /* Assign the policy. */
592 snapshot_session_action
->policy
= copy
;
593 status
= LTTNG_ACTION_STATUS_OK
;
597 lttng_rate_policy_destroy(copy
);
601 enum lttng_action_status
602 lttng_action_snapshot_session_get_rate_policy(const struct lttng_action
*action
,
603 const struct lttng_rate_policy
**policy
)
605 enum lttng_action_status status
;
606 const struct lttng_action_snapshot_session
*snapshot_session_action
;
608 if (!action
|| !policy
|| !IS_SNAPSHOT_SESSION_ACTION(action
)) {
609 status
= LTTNG_ACTION_STATUS_INVALID
;
613 snapshot_session_action
= action_snapshot_session_from_action_const(action
);
615 *policy
= snapshot_session_action
->policy
;
616 status
= LTTNG_ACTION_STATUS_OK
;
621 static const struct lttng_rate_policy
*
622 lttng_action_snapshot_session_internal_get_rate_policy(const struct lttng_action
*action
)
624 const struct lttng_action_snapshot_session
*_action
;
625 _action
= action_snapshot_session_from_action_const(action
);
627 return _action
->policy
;