2 * Copyright (C) 2019 Simon Marchi <simon.marchi@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
9 #include <common/error.h>
10 #include <common/macros.h>
11 #include <common/mi-lttng.h>
12 #include <common/payload-view.h>
13 #include <common/payload.h>
14 #include <common/snapshot.h>
16 #include <lttng/action/action-internal.h>
17 #include <lttng/action/rate-policy-internal.h>
18 #include <lttng/action/rate-policy.h>
19 #include <lttng/action/snapshot-session-internal.h>
20 #include <lttng/action/snapshot-session.h>
21 #include <lttng/snapshot-internal.h>
22 #include <lttng/snapshot.h>
24 #define IS_SNAPSHOT_SESSION_ACTION(action) \
25 (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
59 static const struct lttng_rate_policy
*
60 lttng_action_snapshot_session_internal_get_rate_policy(
61 const struct lttng_action
*action
);
63 static struct lttng_action_snapshot_session
*
64 action_snapshot_session_from_action(struct lttng_action
*action
)
69 action
, struct lttng_action_snapshot_session
, parent
);
72 static const struct lttng_action_snapshot_session
*
73 action_snapshot_session_from_action_const(const struct lttng_action
*action
)
78 action
, struct lttng_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(
109 const struct lttng_action
*_a
, 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 assert(a
->session_name
);
119 assert(b
->session_name
);
120 if (strcmp(a
->session_name
, b
->session_name
)) {
124 if (a
->output
&& b
->output
&&
125 !lttng_snapshot_output_is_equal(a
->output
, b
->output
)) {
127 } else if (!!a
->output
!= !!b
->output
) {
131 is_equal
= lttng_rate_policy_is_equal(a
->policy
, b
->policy
);
136 static size_t serialize_strlen(const char *str
)
138 return str
? strlen(str
) + 1 : 0;
141 static int lttng_action_snapshot_session_serialize(
142 struct lttng_action
*action
, struct lttng_payload
*payload
)
144 struct lttng_action_snapshot_session
*action_snapshot_session
;
145 struct lttng_action_snapshot_session_comm comm
= {};
147 size_t size_before_comm
;
152 size_before_comm
= payload
->buffer
.size
;
154 action_snapshot_session
= action_snapshot_session_from_action(action
);
155 comm
.session_name_len
=
156 serialize_strlen(action_snapshot_session
->session_name
);
159 ret
= lttng_dynamic_buffer_append(
160 &payload
->buffer
, &comm
, sizeof(comm
));
165 assert(action_snapshot_session
->session_name
);
166 DBG("Serializing snapshot session action: session-name: %s",
167 action_snapshot_session
->session_name
);
169 /* Add session name. */
170 ret
= lttng_dynamic_buffer_append(&payload
->buffer
,
171 action_snapshot_session
->session_name
,
172 comm
.session_name_len
);
177 /* Serialize the snapshot output object, if any. */
178 if (action_snapshot_session
->output
) {
179 const size_t size_before_output
= payload
->buffer
.size
;
180 struct lttng_action_snapshot_session_comm
*comm_in_payload
;
182 ret
= lttng_snapshot_output_serialize(
183 action_snapshot_session
->output
,
189 comm_in_payload
= (typeof(comm_in_payload
))(
190 payload
->buffer
.data
+ size_before_comm
);
191 /* Adjust action length in header. */
192 comm_in_payload
->snapshot_output_len
=
193 payload
->buffer
.size
- size_before_output
;
196 /* Serialize the rate policy. */
198 const size_t size_before_output
= payload
->buffer
.size
;
199 struct lttng_action_snapshot_session_comm
*comm_in_payload
;
201 ret
= lttng_rate_policy_serialize(
202 action_snapshot_session
->policy
, payload
);
208 comm_in_payload
= (typeof(comm_in_payload
))(
209 payload
->buffer
.data
+ size_before_comm
);
210 /* Adjust rate policy length in header. */
211 comm_in_payload
->rate_policy_len
=
212 payload
->buffer
.size
- size_before_output
;
219 static void lttng_action_snapshot_session_destroy(struct lttng_action
*action
)
221 struct lttng_action_snapshot_session
*action_snapshot_session
;
227 action_snapshot_session
= action_snapshot_session_from_action(action
);
229 free(action_snapshot_session
->session_name
);
230 lttng_snapshot_output_destroy(action_snapshot_session
->output
);
231 lttng_rate_policy_destroy(action_snapshot_session
->policy
);
232 free(action_snapshot_session
);
238 ssize_t
lttng_action_snapshot_session_create_from_payload(
239 struct lttng_payload_view
*view
,
240 struct lttng_action
**p_action
)
242 ssize_t consumed_len
;
243 const char *variable_data
;
244 struct lttng_action
*action
;
245 enum lttng_action_status status
;
246 struct lttng_snapshot_output
*snapshot_output
= NULL
;
247 struct lttng_rate_policy
*policy
= NULL
;
248 const struct lttng_action_snapshot_session_comm
*comm
;
249 const struct lttng_payload_view snapshot_session_comm_view
=
250 lttng_payload_view_from_view(
251 view
, 0, sizeof(*comm
));
253 action
= lttng_action_snapshot_session_create();
258 if (!lttng_payload_view_is_valid(&snapshot_session_comm_view
)) {
259 /* Payload not large enough to contain the header. */
263 comm
= (typeof(comm
)) snapshot_session_comm_view
.buffer
.data
;
264 variable_data
= (const char *) &comm
->data
;
266 consumed_len
= sizeof(struct lttng_action_snapshot_session_comm
);
268 if (!lttng_buffer_view_contains_string(
269 &view
->buffer
, variable_data
, comm
->session_name_len
)) {
273 status
= lttng_action_snapshot_session_set_session_name(
274 action
, variable_data
);
275 if (status
!= LTTNG_ACTION_STATUS_OK
) {
279 variable_data
+= comm
->session_name_len
;
280 consumed_len
+= comm
->session_name_len
;
282 /* If there is a snapshot output object, deserialize it. */
283 if (comm
->snapshot_output_len
> 0) {
284 ssize_t snapshot_output_consumed_len
;
285 enum lttng_action_status action_status
;
286 struct lttng_payload_view snapshot_output_buffer_view
=
287 lttng_payload_view_from_view(view
, consumed_len
,
288 comm
->snapshot_output_len
);
290 if (!lttng_payload_view_is_valid(&snapshot_output_buffer_view
)) {
291 ERR("Failed to create buffer view for snapshot output.");
295 snapshot_output_consumed_len
=
296 lttng_snapshot_output_create_from_payload(
297 &snapshot_output_buffer_view
,
299 if (snapshot_output_consumed_len
!= comm
->snapshot_output_len
) {
300 ERR("Failed to deserialize snapshot output object: "
301 "consumed-len: %zd, expected-len: %" PRIu32
,
302 snapshot_output_consumed_len
,
303 comm
->snapshot_output_len
);
307 action_status
= lttng_action_snapshot_session_set_output(
308 action
, snapshot_output
);
309 if (action_status
!= LTTNG_ACTION_STATUS_OK
) {
313 /* Ownership has been transferred to the action. */
314 snapshot_output
= NULL
;
317 variable_data
+= comm
->snapshot_output_len
;
318 consumed_len
+= comm
->snapshot_output_len
;
321 if (comm
->rate_policy_len
<= 0) {
322 ERR("Rate policy should be present.");
326 ssize_t rate_policy_consumed_len
;
327 struct lttng_payload_view policy_view
=
328 lttng_payload_view_from_view(view
, consumed_len
,
329 comm
->rate_policy_len
);
331 if (!lttng_payload_view_is_valid(&policy_view
)) {
332 ERR("Failed to create buffer view for rate policy.");
336 rate_policy_consumed_len
=
337 lttng_rate_policy_create_from_payload(
338 &policy_view
, &policy
);
339 if (rate_policy_consumed_len
< 0) {
343 if (rate_policy_consumed_len
!= comm
->rate_policy_len
) {
344 ERR("Failed to deserialize rate policy object: "
345 "consumed-len: %zd, expected-len: %" PRIu32
,
346 rate_policy_consumed_len
,
347 comm
->rate_policy_len
);
351 status
= lttng_action_snapshot_session_set_rate_policy(
353 if (status
!= LTTNG_ACTION_STATUS_OK
) {
358 variable_data
+= comm
->rate_policy_len
;
359 consumed_len
+= comm
->rate_policy_len
;
370 lttng_rate_policy_destroy(policy
);
371 lttng_action_snapshot_session_destroy(action
);
372 lttng_snapshot_output_destroy(snapshot_output
);
377 static enum lttng_error_code
lttng_action_snapshot_session_mi_serialize(
378 const struct lttng_action
*action
, struct mi_writer
*writer
)
381 enum lttng_error_code ret_code
;
382 enum lttng_action_status status
;
383 const char *session_name
= NULL
;
384 const struct lttng_snapshot_output
*output
= NULL
;
385 const struct lttng_rate_policy
*policy
= NULL
;
388 assert(IS_SNAPSHOT_SESSION_ACTION(action
));
390 status
= lttng_action_snapshot_session_get_session_name(
391 action
, &session_name
);
392 assert(status
== LTTNG_ACTION_STATUS_OK
);
393 assert(session_name
!= NULL
);
395 status
= lttng_action_snapshot_session_get_rate_policy(action
, &policy
);
396 assert(status
== LTTNG_ACTION_STATUS_OK
);
397 assert(policy
!= NULL
);
399 /* Open action snapshot session element. */
400 ret
= mi_lttng_writer_open_element(
401 writer
, mi_lttng_element_action_snapshot_session
);
407 ret
= mi_lttng_writer_write_element_string(
408 writer
, mi_lttng_element_session_name
, session_name
);
414 status
= lttng_action_snapshot_session_get_output(action
, &output
);
415 if (status
== LTTNG_ACTION_STATUS_OK
) {
416 assert(output
!= NULL
);
417 ret_code
= lttng_snapshot_output_mi_serialize(output
, writer
);
418 if (ret_code
!= LTTNG_OK
) {
421 } else if (status
!= LTTNG_ACTION_STATUS_UNSET
) {
422 /* This should not happen at this point. */
427 ret_code
= lttng_rate_policy_mi_serialize(policy
, writer
);
428 if (ret_code
!= LTTNG_OK
) {
432 /* Close action_snapshot_session element. */
433 ret
= mi_lttng_writer_close_element(writer
);
442 ret_code
= LTTNG_ERR_MI_IO_FAIL
;
447 struct lttng_action
*lttng_action_snapshot_session_create(void)
449 struct lttng_action
*action
= NULL
;
450 struct lttng_rate_policy
*policy
= NULL
;
451 enum lttng_action_status status
;
453 /* Create a every N = 1 rate policy. */
454 policy
= lttng_rate_policy_every_n_create(1);
459 action
= zmalloc(sizeof(struct lttng_action_snapshot_session
));
464 lttng_action_init(action
, 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(action
, policy
);
474 if (status
!= LTTNG_ACTION_STATUS_OK
) {
481 lttng_rate_policy_destroy(policy
);
485 enum lttng_action_status
lttng_action_snapshot_session_set_session_name(
486 struct lttng_action
*action
, const char *session_name
)
488 struct lttng_action_snapshot_session
*action_snapshot_session
;
489 enum lttng_action_status status
;
491 if (!action
|| !IS_SNAPSHOT_SESSION_ACTION(action
) || !session_name
||
492 strlen(session_name
) == 0) {
493 status
= LTTNG_ACTION_STATUS_INVALID
;
497 action_snapshot_session
= action_snapshot_session_from_action(action
);
499 free(action_snapshot_session
->session_name
);
501 action_snapshot_session
->session_name
= strdup(session_name
);
502 if (!action_snapshot_session
->session_name
) {
503 status
= LTTNG_ACTION_STATUS_ERROR
;
507 status
= LTTNG_ACTION_STATUS_OK
;
512 enum lttng_action_status
lttng_action_snapshot_session_get_session_name(
513 const struct lttng_action
*action
, const char **session_name
)
515 const struct lttng_action_snapshot_session
*action_snapshot_session
;
516 enum lttng_action_status status
;
518 if (!action
|| !IS_SNAPSHOT_SESSION_ACTION(action
) || !session_name
) {
519 status
= LTTNG_ACTION_STATUS_INVALID
;
523 action_snapshot_session
= action_snapshot_session_from_action_const(action
);
525 if (action_snapshot_session
->session_name
) {
526 *session_name
= action_snapshot_session
->session_name
;
527 status
= LTTNG_ACTION_STATUS_OK
;
529 status
= LTTNG_ACTION_STATUS_UNSET
;
537 enum lttng_action_status
lttng_action_snapshot_session_set_output(
538 struct lttng_action
*action
,
539 struct lttng_snapshot_output
*output
)
541 struct lttng_action_snapshot_session
*action_snapshot_session
;
542 enum lttng_action_status status
;
544 if (!action
|| !IS_SNAPSHOT_SESSION_ACTION(action
) || !output
) {
545 status
= LTTNG_ACTION_STATUS_INVALID
;
549 action_snapshot_session
= action_snapshot_session_from_action(action
);
551 lttng_snapshot_output_destroy(action_snapshot_session
->output
);
552 action_snapshot_session
->output
= output
;
554 status
= LTTNG_ACTION_STATUS_OK
;
560 enum lttng_action_status
lttng_action_snapshot_session_get_output(
561 const struct lttng_action
*action
,
562 const struct lttng_snapshot_output
**output
)
564 const struct lttng_action_snapshot_session
*action_snapshot_session
;
565 enum lttng_action_status status
;
567 if (!action
|| !IS_SNAPSHOT_SESSION_ACTION(action
)|| !output
) {
568 status
= LTTNG_ACTION_STATUS_INVALID
;
572 action_snapshot_session
= action_snapshot_session_from_action_const(action
);
574 if (action_snapshot_session
->output
) {
575 *output
= action_snapshot_session
->output
;
576 status
= LTTNG_ACTION_STATUS_OK
;
578 status
= LTTNG_ACTION_STATUS_UNSET
;
585 enum lttng_action_status
lttng_action_snapshot_session_set_rate_policy(
586 struct lttng_action
*action
,
587 const struct lttng_rate_policy
*policy
)
589 enum lttng_action_status status
;
590 struct lttng_action_snapshot_session
*snapshot_session_action
;
591 struct lttng_rate_policy
*copy
= NULL
;
593 if (!action
|| !policy
|| !IS_SNAPSHOT_SESSION_ACTION(action
)) {
594 status
= LTTNG_ACTION_STATUS_INVALID
;
598 copy
= lttng_rate_policy_copy(policy
);
600 status
= LTTNG_ACTION_STATUS_ERROR
;
604 snapshot_session_action
= action_snapshot_session_from_action(action
);
606 /* Free the previous rate policy .*/
607 lttng_rate_policy_destroy(snapshot_session_action
->policy
);
609 /* Assign the policy. */
610 snapshot_session_action
->policy
= copy
;
611 status
= LTTNG_ACTION_STATUS_OK
;
615 lttng_rate_policy_destroy(copy
);
619 enum lttng_action_status
lttng_action_snapshot_session_get_rate_policy(
620 const struct lttng_action
*action
,
621 const struct lttng_rate_policy
**policy
)
623 enum lttng_action_status status
;
624 const struct lttng_action_snapshot_session
*snapshot_session_action
;
626 if (!action
|| !policy
|| !IS_SNAPSHOT_SESSION_ACTION(action
)) {
627 status
= LTTNG_ACTION_STATUS_INVALID
;
631 snapshot_session_action
=
632 action_snapshot_session_from_action_const(action
);
634 *policy
= snapshot_session_action
->policy
;
635 status
= LTTNG_ACTION_STATUS_OK
;
640 static const struct lttng_rate_policy
*
641 lttng_action_snapshot_session_internal_get_rate_policy(
642 const struct lttng_action
*action
)
644 const struct lttng_action_snapshot_session
*_action
;
645 _action
= action_snapshot_session_from_action_const(action
);
647 return _action
->policy
;