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/payload-view.h>
12 #include <common/payload.h>
13 #include <common/snapshot.h>
15 #include <lttng/action/action-internal.h>
16 #include <lttng/action/firing-policy-internal.h>
17 #include <lttng/action/firing-policy.h>
18 #include <lttng/action/snapshot-session-internal.h>
19 #include <lttng/action/snapshot-session.h>
20 #include <lttng/snapshot-internal.h>
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_firing_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 firing_policy_len
;
49 * Variable data (all strings are null-terminated):
51 * - session name string
52 * - snapshot output object
58 static struct lttng_action_snapshot_session
*
59 action_snapshot_session_from_action(struct lttng_action
*action
)
64 action
, struct lttng_action_snapshot_session
, parent
);
67 static const struct lttng_action_snapshot_session
*
68 action_snapshot_session_from_action_const(const struct lttng_action
*action
)
73 action
, struct lttng_action_snapshot_session
, parent
);
76 static bool lttng_action_snapshot_session_validate(struct lttng_action
*action
)
79 struct lttng_action_snapshot_session
*action_snapshot_session
;
85 action_snapshot_session
= action_snapshot_session_from_action(action
);
87 /* A non-empty session name is mandatory. */
88 if (!action_snapshot_session
->session_name
||
89 strlen(action_snapshot_session
->session_name
) == 0) {
93 if (action_snapshot_session
->output
&&
94 !lttng_snapshot_output_validate(action_snapshot_session
->output
)) {
103 static bool lttng_action_snapshot_session_is_equal(
104 const struct lttng_action
*_a
, const struct lttng_action
*_b
)
106 bool is_equal
= false;
107 const struct lttng_action_snapshot_session
*a
, *b
;
109 a
= action_snapshot_session_from_action_const(_a
);
110 b
= action_snapshot_session_from_action_const(_b
);
112 /* Action is not valid if this is not true. */
113 assert(a
->session_name
);
114 assert(b
->session_name
);
115 if (strcmp(a
->session_name
, b
->session_name
)) {
119 if (a
->output
&& b
->output
&&
120 !lttng_snapshot_output_is_equal(a
->output
, b
->output
)) {
122 } else if (!!a
->output
!= !!b
->output
) {
126 is_equal
= lttng_firing_policy_is_equal(a
->policy
, b
->policy
);
131 static size_t serialize_strlen(const char *str
)
133 return str
? strlen(str
) + 1 : 0;
136 static int lttng_action_snapshot_session_serialize(
137 struct lttng_action
*action
, struct lttng_payload
*payload
)
139 struct lttng_action_snapshot_session
*action_snapshot_session
;
140 struct lttng_action_snapshot_session_comm comm
= {};
142 size_t size_before_comm
;
147 size_before_comm
= payload
->buffer
.size
;
149 action_snapshot_session
= action_snapshot_session_from_action(action
);
150 comm
.session_name_len
=
151 serialize_strlen(action_snapshot_session
->session_name
);
154 ret
= lttng_dynamic_buffer_append(
155 &payload
->buffer
, &comm
, sizeof(comm
));
160 assert(action_snapshot_session
->session_name
);
161 DBG("Serializing snapshot session action: session-name: %s",
162 action_snapshot_session
->session_name
);
164 /* Add session name. */
165 ret
= lttng_dynamic_buffer_append(&payload
->buffer
,
166 action_snapshot_session
->session_name
,
167 comm
.session_name_len
);
172 /* Serialize the snapshot output object, if any. */
173 if (action_snapshot_session
->output
) {
174 const size_t size_before_output
= payload
->buffer
.size
;
175 struct lttng_action_snapshot_session_comm
*comm_in_payload
;
177 ret
= lttng_snapshot_output_serialize(
178 action_snapshot_session
->output
,
184 comm_in_payload
= (typeof(comm_in_payload
))(
185 payload
->buffer
.data
+ size_before_comm
);
186 /* Adjust action length in header. */
187 comm_in_payload
->snapshot_output_len
=
188 payload
->buffer
.size
- size_before_output
;
191 /* Serialize the firing policy. */
193 const size_t size_before_output
= payload
->buffer
.size
;
194 struct lttng_action_snapshot_session_comm
*comm_in_payload
;
196 ret
= lttng_firing_policy_serialize(
197 action_snapshot_session
->policy
, payload
);
203 comm_in_payload
= (typeof(comm_in_payload
))(
204 payload
->buffer
.data
+ size_before_comm
);
205 /* Adjust firing policy length in header. */
206 comm_in_payload
->firing_policy_len
=
207 payload
->buffer
.size
- size_before_output
;
214 static void lttng_action_snapshot_session_destroy(struct lttng_action
*action
)
216 struct lttng_action_snapshot_session
*action_snapshot_session
;
222 action_snapshot_session
= action_snapshot_session_from_action(action
);
224 free(action_snapshot_session
->session_name
);
225 lttng_snapshot_output_destroy(action_snapshot_session
->output
);
226 lttng_firing_policy_destroy(action_snapshot_session
->policy
);
227 free(action_snapshot_session
);
233 ssize_t
lttng_action_snapshot_session_create_from_payload(
234 struct lttng_payload_view
*view
,
235 struct lttng_action
**p_action
)
237 ssize_t consumed_len
;
238 const char *variable_data
;
239 struct lttng_action
*action
;
240 enum lttng_action_status status
;
241 struct lttng_snapshot_output
*snapshot_output
= NULL
;
242 struct lttng_firing_policy
*policy
= NULL
;
243 const struct lttng_action_snapshot_session_comm
*comm
;
244 const struct lttng_payload_view snapshot_session_comm_view
=
245 lttng_payload_view_from_view(
246 view
, 0, sizeof(*comm
));
248 action
= lttng_action_snapshot_session_create();
253 if (!lttng_payload_view_is_valid(&snapshot_session_comm_view
)) {
254 /* Payload not large enough to contain the header. */
258 comm
= (typeof(comm
)) snapshot_session_comm_view
.buffer
.data
;
259 variable_data
= (const char *) &comm
->data
;
261 consumed_len
= sizeof(struct lttng_action_snapshot_session_comm
);
263 if (!lttng_buffer_view_contains_string(
264 &view
->buffer
, variable_data
, comm
->session_name_len
)) {
268 status
= lttng_action_snapshot_session_set_session_name(
269 action
, variable_data
);
270 if (status
!= LTTNG_ACTION_STATUS_OK
) {
274 variable_data
+= comm
->session_name_len
;
275 consumed_len
+= comm
->session_name_len
;
277 /* If there is a snapshot output object, deserialize it. */
278 if (comm
->snapshot_output_len
> 0) {
279 ssize_t snapshot_output_consumed_len
;
280 enum lttng_action_status action_status
;
281 struct lttng_payload_view snapshot_output_buffer_view
=
282 lttng_payload_view_from_view(view
, consumed_len
,
283 comm
->snapshot_output_len
);
285 if (!lttng_payload_view_is_valid(&snapshot_output_buffer_view
)) {
286 ERR("Failed to create buffer view for snapshot output.");
290 snapshot_output_consumed_len
=
291 lttng_snapshot_output_create_from_payload(
292 &snapshot_output_buffer_view
,
294 if (snapshot_output_consumed_len
!= comm
->snapshot_output_len
) {
295 ERR("Failed to deserialize snapshot output object: "
296 "consumed-len: %zd, expected-len: %" PRIu32
,
297 snapshot_output_consumed_len
,
298 comm
->snapshot_output_len
);
302 action_status
= lttng_action_snapshot_session_set_output(
303 action
, snapshot_output
);
304 if (action_status
!= LTTNG_ACTION_STATUS_OK
) {
308 /* Ownership has been transferred to the action. */
309 snapshot_output
= NULL
;
312 variable_data
+= comm
->snapshot_output_len
;
313 consumed_len
+= comm
->snapshot_output_len
;
316 if (comm
->firing_policy_len
<= 0) {
317 ERR("Firing policy should be present.");
321 ssize_t firing_policy_consumed_len
;
322 struct lttng_payload_view policy_view
=
323 lttng_payload_view_from_view(view
, consumed_len
,
324 comm
->firing_policy_len
);
326 if (!lttng_payload_view_is_valid(&policy_view
)) {
327 ERR("Failed to create buffer view for firing policy.");
331 firing_policy_consumed_len
=
332 lttng_firing_policy_create_from_payload(
333 &policy_view
, &policy
);
334 if (firing_policy_consumed_len
< 0) {
338 if (firing_policy_consumed_len
!= comm
->firing_policy_len
) {
339 ERR("Failed to deserialize firing policy object: "
340 "consumed-len: %zd, expected-len: %" PRIu32
,
341 firing_policy_consumed_len
,
342 comm
->firing_policy_len
);
346 status
= lttng_action_snapshot_session_set_firing_policy(
348 if (status
!= LTTNG_ACTION_STATUS_OK
) {
353 variable_data
+= comm
->firing_policy_len
;
354 consumed_len
+= comm
->firing_policy_len
;
365 lttng_firing_policy_destroy(policy
);
366 lttng_action_snapshot_session_destroy(action
);
367 lttng_snapshot_output_destroy(snapshot_output
);
372 struct lttng_action
*lttng_action_snapshot_session_create(void)
374 struct lttng_action
*action
= NULL
;
375 struct lttng_firing_policy
*policy
= NULL
;
376 enum lttng_action_status status
;
378 /* Create a every N = 1 firing policy. */
379 policy
= lttng_firing_policy_every_n_create(1);
384 action
= zmalloc(sizeof(struct lttng_action_snapshot_session
));
389 lttng_action_init(action
, LTTNG_ACTION_TYPE_SNAPSHOT_SESSION
,
390 lttng_action_snapshot_session_validate
,
391 lttng_action_snapshot_session_serialize
,
392 lttng_action_snapshot_session_is_equal
,
393 lttng_action_snapshot_session_destroy
);
395 status
= lttng_action_snapshot_session_set_firing_policy(
397 if (status
!= LTTNG_ACTION_STATUS_OK
) {
404 lttng_firing_policy_destroy(policy
);
408 enum lttng_action_status
lttng_action_snapshot_session_set_session_name(
409 struct lttng_action
*action
, const char *session_name
)
411 struct lttng_action_snapshot_session
*action_snapshot_session
;
412 enum lttng_action_status status
;
414 if (!action
|| !IS_SNAPSHOT_SESSION_ACTION(action
) || !session_name
||
415 strlen(session_name
) == 0) {
416 status
= LTTNG_ACTION_STATUS_INVALID
;
420 action_snapshot_session
= action_snapshot_session_from_action(action
);
422 free(action_snapshot_session
->session_name
);
424 action_snapshot_session
->session_name
= strdup(session_name
);
425 if (!action_snapshot_session
->session_name
) {
426 status
= LTTNG_ACTION_STATUS_ERROR
;
430 status
= LTTNG_ACTION_STATUS_OK
;
435 enum lttng_action_status
lttng_action_snapshot_session_get_session_name(
436 const struct lttng_action
*action
, const char **session_name
)
438 const struct lttng_action_snapshot_session
*action_snapshot_session
;
439 enum lttng_action_status status
;
441 if (!action
|| !IS_SNAPSHOT_SESSION_ACTION(action
) || !session_name
) {
442 status
= LTTNG_ACTION_STATUS_INVALID
;
446 action_snapshot_session
= action_snapshot_session_from_action_const(action
);
448 if (action_snapshot_session
->session_name
) {
449 *session_name
= action_snapshot_session
->session_name
;
450 status
= LTTNG_ACTION_STATUS_OK
;
452 status
= LTTNG_ACTION_STATUS_UNSET
;
460 enum lttng_action_status
lttng_action_snapshot_session_set_output(
461 struct lttng_action
*action
,
462 struct lttng_snapshot_output
*output
)
464 struct lttng_action_snapshot_session
*action_snapshot_session
;
465 enum lttng_action_status status
;
467 if (!action
|| !IS_SNAPSHOT_SESSION_ACTION(action
) || !output
) {
468 status
= LTTNG_ACTION_STATUS_INVALID
;
472 action_snapshot_session
= action_snapshot_session_from_action(action
);
474 lttng_snapshot_output_destroy(action_snapshot_session
->output
);
475 action_snapshot_session
->output
= output
;
477 status
= LTTNG_ACTION_STATUS_OK
;
483 enum lttng_action_status
lttng_action_snapshot_session_get_output(
484 const struct lttng_action
*action
,
485 const struct lttng_snapshot_output
**output
)
487 const struct lttng_action_snapshot_session
*action_snapshot_session
;
488 enum lttng_action_status status
;
490 if (!action
|| !IS_SNAPSHOT_SESSION_ACTION(action
)|| !output
) {
491 status
= LTTNG_ACTION_STATUS_INVALID
;
495 action_snapshot_session
= action_snapshot_session_from_action_const(action
);
497 if (action_snapshot_session
->output
) {
498 *output
= action_snapshot_session
->output
;
499 status
= LTTNG_ACTION_STATUS_OK
;
501 status
= LTTNG_ACTION_STATUS_UNSET
;
508 enum lttng_action_status
lttng_action_snapshot_session_set_firing_policy(
509 struct lttng_action
*action
,
510 const struct lttng_firing_policy
*policy
)
512 enum lttng_action_status status
;
513 struct lttng_action_snapshot_session
*snapshot_session_action
;
514 struct lttng_firing_policy
*copy
= NULL
;
516 if (!action
|| !policy
|| !IS_SNAPSHOT_SESSION_ACTION(action
)) {
517 status
= LTTNG_ACTION_STATUS_INVALID
;
521 copy
= lttng_firing_policy_copy(policy
);
523 status
= LTTNG_ACTION_STATUS_ERROR
;
527 snapshot_session_action
= action_snapshot_session_from_action(action
);
529 /* Free the previous firing policy .*/
530 lttng_firing_policy_destroy(snapshot_session_action
->policy
);
532 /* Assign the policy. */
533 snapshot_session_action
->policy
= copy
;
534 status
= LTTNG_ACTION_STATUS_OK
;
538 lttng_firing_policy_destroy(copy
);
542 enum lttng_action_status
lttng_action_snapshot_session_get_firing_policy(
543 const struct lttng_action
*action
,
544 const struct lttng_firing_policy
**policy
)
546 enum lttng_action_status status
;
547 const struct lttng_action_snapshot_session
*snapshot_session_action
;
549 if (!action
|| !policy
|| !IS_SNAPSHOT_SESSION_ACTION(action
)) {
550 status
= LTTNG_ACTION_STATUS_INVALID
;
554 snapshot_session_action
=
555 action_snapshot_session_from_action_const(action
);
557 *policy
= snapshot_session_action
->policy
;
558 status
= LTTNG_ACTION_STATUS_OK
;