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/snapshot.h>
12 #include <common/payload.h>
13 #include <common/payload-view.h>
14 #include <lttng/action/action-internal.h>
15 #include <lttng/action/snapshot-session-internal.h>
16 #include <lttng/action/snapshot-session.h>
17 #include <lttng/snapshot.h>
18 #include <lttng/snapshot-internal.h>
21 #define IS_SNAPSHOT_SESSION_ACTION(action) \
22 (lttng_action_get_type(action) == LTTNG_ACTION_TYPE_SNAPSHOT_SESSION)
24 struct lttng_action_snapshot_session
{
25 struct lttng_action parent
;
31 * When non-NULL, use this custom output when taking the snapshot,
32 * rather than the session's registered snapshot output.
36 struct lttng_snapshot_output
*output
;
39 struct lttng_action_snapshot_session_comm
{
40 /* All string lengths include the trailing \0. */
41 uint32_t session_name_len
;
42 uint32_t snapshot_output_len
;
45 * Variable data (all strings are null-terminated):
47 * - session name string
48 * - snapshot output object
54 static struct lttng_action_snapshot_session
*
55 action_snapshot_session_from_action(struct lttng_action
*action
)
60 action
, struct lttng_action_snapshot_session
, parent
);
63 static const struct lttng_action_snapshot_session
*
64 action_snapshot_session_from_action_const(const struct lttng_action
*action
)
69 action
, struct lttng_action_snapshot_session
, parent
);
72 static bool lttng_action_snapshot_session_validate(struct lttng_action
*action
)
75 struct lttng_action_snapshot_session
*action_snapshot_session
;
81 action_snapshot_session
= action_snapshot_session_from_action(action
);
83 /* A non-empty session name is mandatory. */
84 if (!action_snapshot_session
->session_name
||
85 strlen(action_snapshot_session
->session_name
) == 0) {
89 if (action_snapshot_session
->output
&&
90 !lttng_snapshot_output_validate(action_snapshot_session
->output
)) {
99 static bool lttng_action_snapshot_session_is_equal(
100 const struct lttng_action
*_a
, const struct lttng_action
*_b
)
102 bool is_equal
= false;
103 const struct lttng_action_snapshot_session
*a
, *b
;
105 a
= action_snapshot_session_from_action_const(_a
);
106 b
= action_snapshot_session_from_action_const(_b
);
108 /* Action is not valid if this is not true. */
109 assert(a
->session_name
);
110 assert(b
->session_name
);
111 if (strcmp(a
->session_name
, b
->session_name
)) {
115 if (a
->output
&& b
->output
&&
116 !lttng_snapshot_output_is_equal(a
->output
, b
->output
)) {
118 } else if (!!a
->output
!= !!b
->output
) {
127 static size_t serialize_strlen(const char *str
)
129 return str
? strlen(str
) + 1 : 0;
132 static int lttng_action_snapshot_session_serialize(
133 struct lttng_action
*action
, struct lttng_payload
*payload
)
135 struct lttng_action_snapshot_session
*action_snapshot_session
;
136 struct lttng_action_snapshot_session_comm comm
= {};
138 size_t size_before_comm
;
143 size_before_comm
= payload
->buffer
.size
;
145 action_snapshot_session
= action_snapshot_session_from_action(action
);
146 comm
.session_name_len
=
147 serialize_strlen(action_snapshot_session
->session_name
);
150 ret
= lttng_dynamic_buffer_append(
151 &payload
->buffer
, &comm
, sizeof(comm
));
156 assert(action_snapshot_session
->session_name
);
157 DBG("Serializing snapshot session action: session-name: %s",
158 action_snapshot_session
->session_name
);
160 /* Add session name. */
161 ret
= lttng_dynamic_buffer_append(&payload
->buffer
,
162 action_snapshot_session
->session_name
,
163 comm
.session_name_len
);
168 /* Serialize the snapshot output object, if any. */
169 if (action_snapshot_session
->output
) {
170 const size_t size_before_output
= payload
->buffer
.size
;
171 struct lttng_action_snapshot_session_comm
*comm_in_payload
;
173 ret
= lttng_snapshot_output_serialize(
174 action_snapshot_session
->output
,
180 /* Adjust action length in header. */
181 comm_in_payload
= (typeof(comm_in_payload
))(
182 payload
->buffer
.data
+ size_before_comm
);
183 comm_in_payload
->snapshot_output_len
=
184 payload
->buffer
.size
- size_before_output
;
191 static void lttng_action_snapshot_session_destroy(struct lttng_action
*action
)
193 struct lttng_action_snapshot_session
*action_snapshot_session
;
199 action_snapshot_session
= action_snapshot_session_from_action(action
);
201 free(action_snapshot_session
->session_name
);
202 lttng_snapshot_output_destroy(action_snapshot_session
->output
);
203 free(action_snapshot_session
);
209 ssize_t
lttng_action_snapshot_session_create_from_payload(
210 struct lttng_payload_view
*view
,
211 struct lttng_action
**p_action
)
213 ssize_t consumed_len
;
214 const char *variable_data
;
215 struct lttng_action
*action
;
216 enum lttng_action_status status
;
217 struct lttng_snapshot_output
*snapshot_output
= NULL
;
218 const struct lttng_action_snapshot_session_comm
*comm
;
219 const struct lttng_payload_view snapshot_session_comm_view
=
220 lttng_payload_view_from_view(
221 view
, 0, sizeof(*comm
));
223 action
= lttng_action_snapshot_session_create();
228 if (!lttng_payload_view_is_valid(&snapshot_session_comm_view
)) {
229 /* Payload not large enough to contain the header. */
233 comm
= (typeof(comm
)) snapshot_session_comm_view
.buffer
.data
;
234 variable_data
= (const char *) &comm
->data
;
236 consumed_len
= sizeof(struct lttng_action_snapshot_session_comm
);
238 if (!lttng_buffer_view_contains_string(
239 &view
->buffer
, variable_data
, comm
->session_name_len
)) {
243 status
= lttng_action_snapshot_session_set_session_name(
244 action
, variable_data
);
245 if (status
!= LTTNG_ACTION_STATUS_OK
) {
249 variable_data
+= comm
->session_name_len
;
250 consumed_len
+= comm
->session_name_len
;
252 /* If there is a snapshot output object, deserialize it. */
253 if (comm
->snapshot_output_len
> 0) {
254 ssize_t snapshot_output_consumed_len
;
255 enum lttng_action_status action_status
;
256 struct lttng_payload_view snapshot_output_buffer_view
=
257 lttng_payload_view_from_view(view
, consumed_len
,
258 comm
->snapshot_output_len
);
260 if (!lttng_payload_view_is_valid(&snapshot_output_buffer_view
)) {
261 ERR("Failed to create buffer view for snapshot output.");
265 snapshot_output_consumed_len
=
266 lttng_snapshot_output_create_from_payload(
267 &snapshot_output_buffer_view
,
269 if (snapshot_output_consumed_len
!= comm
->snapshot_output_len
) {
270 ERR("Failed to deserialize snapshot output object: "
271 "consumed-len: %zd, expected-len: %" PRIu32
,
272 snapshot_output_consumed_len
,
273 comm
->snapshot_output_len
);
277 action_status
= lttng_action_snapshot_session_set_output(
278 action
, snapshot_output
);
279 if (action_status
!= LTTNG_ACTION_STATUS_OK
) {
283 /* Ownership has been transferred to the action. */
284 snapshot_output
= NULL
;
287 variable_data
+= comm
->snapshot_output_len
;
288 consumed_len
+= comm
->snapshot_output_len
;
298 lttng_action_snapshot_session_destroy(action
);
299 lttng_snapshot_output_destroy(snapshot_output
);
304 struct lttng_action
*lttng_action_snapshot_session_create(void)
306 struct lttng_action
*action
;
308 action
= zmalloc(sizeof(struct lttng_action_snapshot_session
));
313 lttng_action_init(action
, LTTNG_ACTION_TYPE_SNAPSHOT_SESSION
,
314 lttng_action_snapshot_session_validate
,
315 lttng_action_snapshot_session_serialize
,
316 lttng_action_snapshot_session_is_equal
,
317 lttng_action_snapshot_session_destroy
);
323 enum lttng_action_status
lttng_action_snapshot_session_set_session_name(
324 struct lttng_action
*action
, const char *session_name
)
326 struct lttng_action_snapshot_session
*action_snapshot_session
;
327 enum lttng_action_status status
;
329 if (!action
|| !IS_SNAPSHOT_SESSION_ACTION(action
) || !session_name
||
330 strlen(session_name
) == 0) {
331 status
= LTTNG_ACTION_STATUS_INVALID
;
335 action_snapshot_session
= action_snapshot_session_from_action(action
);
337 free(action_snapshot_session
->session_name
);
339 action_snapshot_session
->session_name
= strdup(session_name
);
340 if (!action_snapshot_session
->session_name
) {
341 status
= LTTNG_ACTION_STATUS_ERROR
;
345 status
= LTTNG_ACTION_STATUS_OK
;
350 enum lttng_action_status
lttng_action_snapshot_session_get_session_name(
351 const struct lttng_action
*action
, const char **session_name
)
353 const struct lttng_action_snapshot_session
*action_snapshot_session
;
354 enum lttng_action_status status
;
356 if (!action
|| !IS_SNAPSHOT_SESSION_ACTION(action
) || !session_name
) {
357 status
= LTTNG_ACTION_STATUS_INVALID
;
361 action_snapshot_session
= action_snapshot_session_from_action_const(action
);
363 if (action_snapshot_session
->session_name
) {
364 *session_name
= action_snapshot_session
->session_name
;
365 status
= LTTNG_ACTION_STATUS_OK
;
367 status
= LTTNG_ACTION_STATUS_UNSET
;
375 enum lttng_action_status
lttng_action_snapshot_session_set_output(
376 struct lttng_action
*action
,
377 struct lttng_snapshot_output
*output
)
379 struct lttng_action_snapshot_session
*action_snapshot_session
;
380 enum lttng_action_status status
;
382 if (!action
|| !IS_SNAPSHOT_SESSION_ACTION(action
) || !output
) {
383 status
= LTTNG_ACTION_STATUS_INVALID
;
387 action_snapshot_session
= action_snapshot_session_from_action(action
);
389 lttng_snapshot_output_destroy(action_snapshot_session
->output
);
390 action_snapshot_session
->output
= output
;
392 status
= LTTNG_ACTION_STATUS_OK
;
398 enum lttng_action_status
lttng_action_snapshot_session_get_output(
399 const struct lttng_action
*action
,
400 const struct lttng_snapshot_output
**output
)
402 const struct lttng_action_snapshot_session
*action_snapshot_session
;
403 enum lttng_action_status status
;
405 if (!action
|| !IS_SNAPSHOT_SESSION_ACTION(action
)|| !output
) {
406 status
= LTTNG_ACTION_STATUS_INVALID
;
410 action_snapshot_session
= action_snapshot_session_from_action_const(action
);
412 if (action_snapshot_session
->output
) {
413 *output
= action_snapshot_session
->output
;
414 status
= LTTNG_ACTION_STATUS_OK
;
416 status
= LTTNG_ACTION_STATUS_UNSET
;