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)
26 struct lttng_action_snapshot_session
{
27 struct lttng_action parent
;
33 * When non-NULL, use this custom output when taking the snapshot,
34 * rather than the session's registered snapshot output.
38 struct lttng_snapshot_output
*output
;
39 struct lttng_rate_policy
*policy
;
42 struct 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
;
46 uint32_t rate_policy_len
;
49 * Variable data (all strings are null-terminated):
51 * - session name string
52 * - snapshot output object
58 static const struct lttng_rate_policy
*
59 lttng_action_snapshot_session_internal_get_rate_policy(
60 const struct lttng_action
*action
);
62 static struct lttng_action_snapshot_session
*
63 action_snapshot_session_from_action(struct lttng_action
*action
)
68 action
, struct lttng_action_snapshot_session
, parent
);
71 static const struct lttng_action_snapshot_session
*
72 action_snapshot_session_from_action_const(const struct lttng_action
*action
)
77 action
, struct lttng_action_snapshot_session
, parent
);
80 static bool lttng_action_snapshot_session_validate(struct lttng_action
*action
)
83 struct lttng_action_snapshot_session
*action_snapshot_session
;
89 action_snapshot_session
= action_snapshot_session_from_action(action
);
91 /* A non-empty session name is mandatory. */
92 if (!action_snapshot_session
->session_name
||
93 strlen(action_snapshot_session
->session_name
) == 0) {
97 if (action_snapshot_session
->output
&&
98 !lttng_snapshot_output_validate(action_snapshot_session
->output
)) {
107 static bool lttng_action_snapshot_session_is_equal(
108 const struct lttng_action
*_a
, const struct lttng_action
*_b
)
110 bool is_equal
= false;
111 const struct lttng_action_snapshot_session
*a
, *b
;
113 a
= action_snapshot_session_from_action_const(_a
);
114 b
= action_snapshot_session_from_action_const(_b
);
116 /* Action is not valid if this is not true. */
117 LTTNG_ASSERT(a
->session_name
);
118 LTTNG_ASSERT(b
->session_name
);
119 if (strcmp(a
->session_name
, b
->session_name
)) {
123 if (a
->output
&& b
->output
&&
124 !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(
141 struct lttng_action
*action
, 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
=
155 serialize_strlen(action_snapshot_session
->session_name
);
158 ret
= lttng_dynamic_buffer_append(
159 &payload
->buffer
, &comm
, sizeof(comm
));
164 LTTNG_ASSERT(action_snapshot_session
->session_name
);
165 DBG("Serializing snapshot session action: session-name: %s",
166 action_snapshot_session
->session_name
);
168 /* Add session name. */
169 ret
= lttng_dynamic_buffer_append(&payload
->buffer
,
170 action_snapshot_session
->session_name
,
171 comm
.session_name_len
);
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
;
181 ret
= lttng_snapshot_output_serialize(
182 action_snapshot_session
->output
,
188 comm_in_payload
= (typeof(comm_in_payload
))(
189 payload
->buffer
.data
+ size_before_comm
);
190 /* Adjust action length in header. */
191 comm_in_payload
->snapshot_output_len
=
192 payload
->buffer
.size
- size_before_output
;
195 /* Serialize the rate policy. */
197 const size_t size_before_output
= payload
->buffer
.size
;
198 struct lttng_action_snapshot_session_comm
*comm_in_payload
;
200 ret
= lttng_rate_policy_serialize(
201 action_snapshot_session
->policy
, payload
);
207 comm_in_payload
= (typeof(comm_in_payload
))(
208 payload
->buffer
.data
+ size_before_comm
);
209 /* Adjust rate policy length in header. */
210 comm_in_payload
->rate_policy_len
=
211 payload
->buffer
.size
- size_before_output
;
218 static void lttng_action_snapshot_session_destroy(struct lttng_action
*action
)
220 struct lttng_action_snapshot_session
*action_snapshot_session
;
226 action_snapshot_session
= action_snapshot_session_from_action(action
);
228 free(action_snapshot_session
->session_name
);
229 lttng_snapshot_output_destroy(action_snapshot_session
->output
);
230 lttng_rate_policy_destroy(action_snapshot_session
->policy
);
231 free(action_snapshot_session
);
237 ssize_t
lttng_action_snapshot_session_create_from_payload(
238 struct lttng_payload_view
*view
,
239 struct lttng_action
**p_action
)
241 ssize_t consumed_len
;
242 const char *variable_data
;
243 struct lttng_action
*action
;
244 enum lttng_action_status status
;
245 struct lttng_snapshot_output
*snapshot_output
= NULL
;
246 struct lttng_rate_policy
*policy
= NULL
;
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
));
252 action
= lttng_action_snapshot_session_create();
257 if (!lttng_payload_view_is_valid(&snapshot_session_comm_view
)) {
258 /* Payload not large enough to contain the header. */
262 comm
= (typeof(comm
)) snapshot_session_comm_view
.buffer
.data
;
263 variable_data
= (const char *) &comm
->data
;
265 consumed_len
= sizeof(struct lttng_action_snapshot_session_comm
);
267 if (!lttng_buffer_view_contains_string(
268 &view
->buffer
, variable_data
, comm
->session_name_len
)) {
272 status
= lttng_action_snapshot_session_set_session_name(
273 action
, variable_data
);
274 if (status
!= LTTNG_ACTION_STATUS_OK
) {
278 variable_data
+= comm
->session_name_len
;
279 consumed_len
+= comm
->session_name_len
;
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
);
289 if (!lttng_payload_view_is_valid(&snapshot_output_buffer_view
)) {
290 ERR("Failed to create buffer view for snapshot output.");
294 snapshot_output_consumed_len
=
295 lttng_snapshot_output_create_from_payload(
296 &snapshot_output_buffer_view
,
298 if (snapshot_output_consumed_len
!= comm
->snapshot_output_len
) {
299 ERR("Failed to deserialize snapshot output object: "
300 "consumed-len: %zd, expected-len: %" PRIu32
,
301 snapshot_output_consumed_len
,
302 comm
->snapshot_output_len
);
306 action_status
= lttng_action_snapshot_session_set_output(
307 action
, snapshot_output
);
308 if (action_status
!= LTTNG_ACTION_STATUS_OK
) {
312 /* Ownership has been transferred to the action. */
313 snapshot_output
= NULL
;
316 variable_data
+= comm
->snapshot_output_len
;
317 consumed_len
+= comm
->snapshot_output_len
;
320 if (comm
->rate_policy_len
<= 0) {
321 ERR("Rate policy should be present.");
325 ssize_t rate_policy_consumed_len
;
326 struct lttng_payload_view policy_view
=
327 lttng_payload_view_from_view(view
, consumed_len
,
328 comm
->rate_policy_len
);
330 if (!lttng_payload_view_is_valid(&policy_view
)) {
331 ERR("Failed to create buffer view for rate policy.");
335 rate_policy_consumed_len
=
336 lttng_rate_policy_create_from_payload(
337 &policy_view
, &policy
);
338 if (rate_policy_consumed_len
< 0) {
342 if (rate_policy_consumed_len
!= comm
->rate_policy_len
) {
343 ERR("Failed to deserialize rate policy object: "
344 "consumed-len: %zd, expected-len: %" PRIu32
,
345 rate_policy_consumed_len
,
346 comm
->rate_policy_len
);
350 status
= lttng_action_snapshot_session_set_rate_policy(
352 if (status
!= LTTNG_ACTION_STATUS_OK
) {
357 variable_data
+= comm
->rate_policy_len
;
358 consumed_len
+= comm
->rate_policy_len
;
369 lttng_rate_policy_destroy(policy
);
370 lttng_action_snapshot_session_destroy(action
);
371 lttng_snapshot_output_destroy(snapshot_output
);
376 static enum lttng_error_code
lttng_action_snapshot_session_mi_serialize(
377 const struct lttng_action
*action
, struct mi_writer
*writer
)
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
;
386 LTTNG_ASSERT(action
);
387 LTTNG_ASSERT(IS_SNAPSHOT_SESSION_ACTION(action
));
389 status
= lttng_action_snapshot_session_get_session_name(
390 action
, &session_name
);
391 LTTNG_ASSERT(status
== LTTNG_ACTION_STATUS_OK
);
392 LTTNG_ASSERT(session_name
!= NULL
);
394 status
= lttng_action_snapshot_session_get_rate_policy(action
, &policy
);
395 LTTNG_ASSERT(status
== LTTNG_ACTION_STATUS_OK
);
396 LTTNG_ASSERT(policy
!= NULL
);
398 /* Open action snapshot session element. */
399 ret
= mi_lttng_writer_open_element(
400 writer
, mi_lttng_element_action_snapshot_session
);
406 ret
= mi_lttng_writer_write_element_string(
407 writer
, mi_lttng_element_session_name
, session_name
);
413 status
= lttng_action_snapshot_session_get_output(action
, &output
);
414 if (status
== LTTNG_ACTION_STATUS_OK
) {
415 LTTNG_ASSERT(output
!= NULL
);
416 ret_code
= lttng_snapshot_output_mi_serialize(output
, writer
);
417 if (ret_code
!= LTTNG_OK
) {
420 } else if (status
!= LTTNG_ACTION_STATUS_UNSET
) {
421 /* This should not happen at this point. */
426 ret_code
= lttng_rate_policy_mi_serialize(policy
, writer
);
427 if (ret_code
!= LTTNG_OK
) {
431 /* Close action_snapshot_session element. */
432 ret
= mi_lttng_writer_close_element(writer
);
441 ret_code
= LTTNG_ERR_MI_IO_FAIL
;
446 struct lttng_action
*lttng_action_snapshot_session_create(void)
448 struct lttng_action_snapshot_session
*action_snapshot
= NULL
;
449 struct lttng_rate_policy
*policy
= NULL
;
450 enum lttng_action_status status
;
452 /* Create a every N = 1 rate policy. */
453 policy
= lttng_rate_policy_every_n_create(1);
458 action_snapshot
= zmalloc
<lttng_action_snapshot_session
>();
459 if (!action_snapshot
) {
463 lttng_action_init(&action_snapshot
->parent
,
464 LTTNG_ACTION_TYPE_SNAPSHOT_SESSION
,
465 lttng_action_snapshot_session_validate
,
466 lttng_action_snapshot_session_serialize
,
467 lttng_action_snapshot_session_is_equal
,
468 lttng_action_snapshot_session_destroy
,
469 lttng_action_snapshot_session_internal_get_rate_policy
,
470 lttng_action_generic_add_error_query_results
,
471 lttng_action_snapshot_session_mi_serialize
);
473 status
= lttng_action_snapshot_session_set_rate_policy(
474 &action_snapshot
->parent
, policy
);
475 if (status
!= LTTNG_ACTION_STATUS_OK
) {
476 lttng_action_destroy(&action_snapshot
->parent
);
477 action_snapshot
= NULL
;
482 lttng_rate_policy_destroy(policy
);
483 return action_snapshot
? &action_snapshot
->parent
: nullptr;
486 enum lttng_action_status
lttng_action_snapshot_session_set_session_name(
487 struct lttng_action
*action
, const char *session_name
)
489 struct lttng_action_snapshot_session
*action_snapshot_session
;
490 enum lttng_action_status status
;
492 if (!action
|| !IS_SNAPSHOT_SESSION_ACTION(action
) || !session_name
||
493 strlen(session_name
) == 0) {
494 status
= LTTNG_ACTION_STATUS_INVALID
;
498 action_snapshot_session
= action_snapshot_session_from_action(action
);
500 free(action_snapshot_session
->session_name
);
502 action_snapshot_session
->session_name
= strdup(session_name
);
503 if (!action_snapshot_session
->session_name
) {
504 status
= LTTNG_ACTION_STATUS_ERROR
;
508 status
= LTTNG_ACTION_STATUS_OK
;
513 enum lttng_action_status
lttng_action_snapshot_session_get_session_name(
514 const struct lttng_action
*action
, const char **session_name
)
516 const struct lttng_action_snapshot_session
*action_snapshot_session
;
517 enum lttng_action_status status
;
519 if (!action
|| !IS_SNAPSHOT_SESSION_ACTION(action
) || !session_name
) {
520 status
= LTTNG_ACTION_STATUS_INVALID
;
524 action_snapshot_session
= action_snapshot_session_from_action_const(action
);
526 if (action_snapshot_session
->session_name
) {
527 *session_name
= action_snapshot_session
->session_name
;
528 status
= LTTNG_ACTION_STATUS_OK
;
530 status
= LTTNG_ACTION_STATUS_UNSET
;
538 enum lttng_action_status
lttng_action_snapshot_session_set_output(
539 struct lttng_action
*action
,
540 struct lttng_snapshot_output
*output
)
542 struct lttng_action_snapshot_session
*action_snapshot_session
;
543 enum lttng_action_status status
;
545 if (!action
|| !IS_SNAPSHOT_SESSION_ACTION(action
) || !output
) {
546 status
= LTTNG_ACTION_STATUS_INVALID
;
550 action_snapshot_session
= action_snapshot_session_from_action(action
);
552 lttng_snapshot_output_destroy(action_snapshot_session
->output
);
553 action_snapshot_session
->output
= output
;
555 status
= LTTNG_ACTION_STATUS_OK
;
561 enum lttng_action_status
lttng_action_snapshot_session_get_output(
562 const struct lttng_action
*action
,
563 const struct lttng_snapshot_output
**output
)
565 const struct lttng_action_snapshot_session
*action_snapshot_session
;
566 enum lttng_action_status status
;
568 if (!action
|| !IS_SNAPSHOT_SESSION_ACTION(action
)|| !output
) {
569 status
= LTTNG_ACTION_STATUS_INVALID
;
573 action_snapshot_session
= action_snapshot_session_from_action_const(action
);
575 if (action_snapshot_session
->output
) {
576 *output
= action_snapshot_session
->output
;
577 status
= LTTNG_ACTION_STATUS_OK
;
579 status
= LTTNG_ACTION_STATUS_UNSET
;
586 enum lttng_action_status
lttng_action_snapshot_session_set_rate_policy(
587 struct lttng_action
*action
,
588 const struct lttng_rate_policy
*policy
)
590 enum lttng_action_status status
;
591 struct lttng_action_snapshot_session
*snapshot_session_action
;
592 struct lttng_rate_policy
*copy
= NULL
;
594 if (!action
|| !policy
|| !IS_SNAPSHOT_SESSION_ACTION(action
)) {
595 status
= LTTNG_ACTION_STATUS_INVALID
;
599 copy
= lttng_rate_policy_copy(policy
);
601 status
= LTTNG_ACTION_STATUS_ERROR
;
605 snapshot_session_action
= action_snapshot_session_from_action(action
);
607 /* Free the previous rate policy .*/
608 lttng_rate_policy_destroy(snapshot_session_action
->policy
);
610 /* Assign the policy. */
611 snapshot_session_action
->policy
= copy
;
612 status
= LTTNG_ACTION_STATUS_OK
;
616 lttng_rate_policy_destroy(copy
);
620 enum lttng_action_status
lttng_action_snapshot_session_get_rate_policy(
621 const struct lttng_action
*action
,
622 const struct lttng_rate_policy
**policy
)
624 enum lttng_action_status status
;
625 const struct lttng_action_snapshot_session
*snapshot_session_action
;
627 if (!action
|| !policy
|| !IS_SNAPSHOT_SESSION_ACTION(action
)) {
628 status
= LTTNG_ACTION_STATUS_INVALID
;
632 snapshot_session_action
=
633 action_snapshot_session_from_action_const(action
);
635 *policy
= snapshot_session_action
->policy
;
636 status
= LTTNG_ACTION_STATUS_OK
;
641 static const struct lttng_rate_policy
*
642 lttng_action_snapshot_session_internal_get_rate_policy(
643 const struct lttng_action
*action
)
645 const struct lttng_action_snapshot_session
*_action
;
646 _action
= action_snapshot_session_from_action_const(action
);
648 return _action
->policy
;