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 <lttng/action/action-internal.h>
13 #include <lttng/action/snapshot-session-internal.h>
14 #include <lttng/action/snapshot-session.h>
15 #include <lttng/snapshot.h>
16 #include <lttng/snapshot-internal.h>
19 struct lttng_action_snapshot_session
{
20 struct lttng_action parent
;
26 * When non-NULL, use this custom output when taking the snapshot,
27 * rather than the session's registered snapshot output.
31 struct lttng_snapshot_output
*output
;
34 struct lttng_action_snapshot_session_comm
{
35 /* All string lengths include the trailing \0. */
36 uint32_t session_name_len
;
37 uint32_t snapshot_output_len
;
40 * Variable data (all strings are null-terminated):
42 * - session name string
43 * - snapshot output object
49 static struct lttng_action_snapshot_session
*
50 action_snapshot_session_from_action(struct lttng_action
*action
)
55 action
, struct lttng_action_snapshot_session
, parent
);
58 static const struct lttng_action_snapshot_session
*
59 action_snapshot_session_from_action_const(const struct lttng_action
*action
)
64 action
, struct lttng_action_snapshot_session
, parent
);
67 static bool lttng_action_snapshot_session_validate(struct lttng_action
*action
)
70 struct lttng_action_snapshot_session
*action_snapshot_session
;
76 action_snapshot_session
= action_snapshot_session_from_action(action
);
78 /* A non-empty session name is mandatory. */
79 if (!action_snapshot_session
->session_name
||
80 strlen(action_snapshot_session
->session_name
) == 0) {
84 if (action_snapshot_session
->output
&&
85 !lttng_snapshot_output_validate(action_snapshot_session
->output
)) {
94 static bool lttng_action_snapshot_session_is_equal(const struct lttng_action
*_a
, const struct lttng_action
*_b
)
96 bool is_equal
= false;
97 const struct lttng_action_snapshot_session
*a
, *b
;
99 a
= action_snapshot_session_from_action_const(_a
);
100 b
= action_snapshot_session_from_action_const(_b
);
102 /* Action is not valid if this is not true. */
103 assert(a
->session_name
);
104 assert(b
->session_name
);
105 if (strcmp(a
->session_name
, b
->session_name
)) {
109 if (a
->output
&& b
->output
&&
110 !lttng_snapshot_output_is_equal(a
->output
, b
->output
)) {
112 } else if (!!a
->output
!= !!b
->output
) {
121 static size_t serialize_strlen(const char *s
)
133 static int lttng_action_snapshot_session_serialize(
134 struct lttng_action
*action
, struct lttng_dynamic_buffer
*buf
)
136 struct lttng_action_snapshot_session
*action_snapshot_session
;
137 struct lttng_action_snapshot_session_comm comm
;
138 struct lttng_dynamic_buffer snapshot_output_buf
= { 0 };
144 lttng_dynamic_buffer_init(&snapshot_output_buf
);
146 action_snapshot_session
= action_snapshot_session_from_action(action
);
148 assert(action_snapshot_session
->session_name
);
149 DBG("Serializing snapshot session action: session-name: %s",
150 action_snapshot_session
->session_name
);
152 /* Serialize the snapshot output object first, so we know its length. */
153 if (action_snapshot_session
->output
) {
154 ret
= lttng_snapshot_output_serialize(
155 action_snapshot_session
->output
, &snapshot_output_buf
);
161 comm
.session_name_len
=
162 serialize_strlen(action_snapshot_session
->session_name
);
163 comm
.snapshot_output_len
= snapshot_output_buf
.size
;
165 ret
= lttng_dynamic_buffer_append(buf
, &comm
, sizeof(comm
));
170 ret
= lttng_dynamic_buffer_append(buf
,
171 action_snapshot_session
->session_name
,
172 comm
.session_name_len
);
177 ret
= lttng_dynamic_buffer_append_buffer(buf
, &snapshot_output_buf
);
183 lttng_dynamic_buffer_reset(&snapshot_output_buf
);
187 static void lttng_action_snapshot_session_destroy(struct lttng_action
*action
)
189 struct lttng_action_snapshot_session
*action_snapshot_session
;
195 action_snapshot_session
= action_snapshot_session_from_action(action
);
197 free(action_snapshot_session
->session_name
);
198 lttng_snapshot_output_destroy(action_snapshot_session
->output
);
199 free(action_snapshot_session
);
205 ssize_t
lttng_action_snapshot_session_create_from_buffer(
206 const struct lttng_buffer_view
*view
,
207 struct lttng_action
**p_action
)
209 ssize_t consumed_len
;
210 struct lttng_action_snapshot_session_comm
*comm
;
211 const char *variable_data
;
212 struct lttng_action
*action
;
213 enum lttng_action_status status
;
214 struct lttng_snapshot_output
*snapshot_output
= NULL
;
216 action
= lttng_action_snapshot_session_create();
221 comm
= (struct lttng_action_snapshot_session_comm
*) view
->data
;
222 variable_data
= (const char *) &comm
->data
;
224 consumed_len
= sizeof(struct lttng_action_snapshot_session_comm
);
226 if (!lttng_buffer_view_contains_string(
227 view
, variable_data
, comm
->session_name_len
)) {
231 status
= lttng_action_snapshot_session_set_session_name(
232 action
, variable_data
);
233 if (status
!= LTTNG_ACTION_STATUS_OK
) {
237 variable_data
+= comm
->session_name_len
;
238 consumed_len
+= comm
->session_name_len
;
240 /* If there is a snapshot output object, deserialize it. */
241 if (comm
->snapshot_output_len
> 0) {
242 ssize_t snapshot_output_consumed_len
;
243 enum lttng_action_status action_status
;
244 struct lttng_buffer_view snapshot_output_buffer_view
=
245 lttng_buffer_view_from_view(view
, consumed_len
,
246 comm
->snapshot_output_len
);
247 if (!snapshot_output_buffer_view
.data
) {
248 fprintf(stderr
, "Failed to create buffer view for snapshot output.\n");
252 snapshot_output_consumed_len
=
253 lttng_snapshot_output_create_from_buffer(
254 &snapshot_output_buffer_view
,
256 if (snapshot_output_consumed_len
!= comm
->snapshot_output_len
) {
258 "Failed to deserialize snapshot output object: "
259 "consumed-len: %zd, expected-len: %" PRIu32
,
260 snapshot_output_consumed_len
,
261 comm
->snapshot_output_len
);
265 action_status
= lttng_action_snapshot_session_set_output(
266 action
, snapshot_output
);
267 if (action_status
!= LTTNG_ACTION_STATUS_OK
) {
271 /* Ownership has been transferred to the action. */
272 snapshot_output
= NULL
;
275 variable_data
+= comm
->snapshot_output_len
;
276 consumed_len
+= comm
->snapshot_output_len
;
286 lttng_action_snapshot_session_destroy(action
);
287 lttng_snapshot_output_destroy(snapshot_output
);
292 struct lttng_action
*lttng_action_snapshot_session_create(void)
294 struct lttng_action
*action
;
296 action
= zmalloc(sizeof(struct lttng_action_snapshot_session
));
301 lttng_action_init(action
, LTTNG_ACTION_TYPE_SNAPSHOT_SESSION
,
302 lttng_action_snapshot_session_validate
,
303 lttng_action_snapshot_session_serialize
,
304 lttng_action_snapshot_session_is_equal
,
305 lttng_action_snapshot_session_destroy
);
311 enum lttng_action_status
lttng_action_snapshot_session_set_session_name(
312 struct lttng_action
*action
, const char *session_name
)
314 struct lttng_action_snapshot_session
*action_snapshot_session
;
315 enum lttng_action_status status
;
317 if (!action
|| !session_name
|| strlen(session_name
) == 0) {
318 status
= LTTNG_ACTION_STATUS_INVALID
;
322 action_snapshot_session
= action_snapshot_session_from_action(action
);
324 free(action_snapshot_session
->session_name
);
326 action_snapshot_session
->session_name
= strdup(session_name
);
327 if (!action_snapshot_session
->session_name
) {
328 status
= LTTNG_ACTION_STATUS_ERROR
;
332 status
= LTTNG_ACTION_STATUS_OK
;
337 enum lttng_action_status
lttng_action_snapshot_session_get_session_name(
338 const struct lttng_action
*action
, const char **session_name
)
340 const struct lttng_action_snapshot_session
*action_snapshot_session
;
341 enum lttng_action_status status
;
343 if (!action
|| !session_name
) {
344 status
= LTTNG_ACTION_STATUS_INVALID
;
348 action_snapshot_session
= action_snapshot_session_from_action_const(action
);
350 if (action_snapshot_session
->session_name
) {
351 *session_name
= action_snapshot_session
->session_name
;
352 status
= LTTNG_ACTION_STATUS_OK
;
354 status
= LTTNG_ACTION_STATUS_UNSET
;
362 enum lttng_action_status
lttng_action_snapshot_session_set_output(
363 struct lttng_action
*action
,
364 struct lttng_snapshot_output
*output
)
366 struct lttng_action_snapshot_session
*action_snapshot_session
;
367 enum lttng_action_status status
;
369 if (!action
|| !output
) {
370 status
= LTTNG_ACTION_STATUS_INVALID
;
374 action_snapshot_session
= action_snapshot_session_from_action(action
);
376 lttng_snapshot_output_destroy(action_snapshot_session
->output
);
377 action_snapshot_session
->output
= output
;
379 status
= LTTNG_ACTION_STATUS_OK
;
385 enum lttng_action_status
lttng_action_snapshot_session_get_output_const(
386 const struct lttng_action
*action
,
387 const struct lttng_snapshot_output
**output
)
389 const struct lttng_action_snapshot_session
*action_snapshot_session
;
390 enum lttng_action_status status
;
392 if (!action
|| !output
) {
393 status
= LTTNG_ACTION_STATUS_INVALID
;
397 action_snapshot_session
= action_snapshot_session_from_action_const(action
);
399 if (action_snapshot_session
->output
) {
400 *output
= action_snapshot_session
->output
;
401 status
= LTTNG_ACTION_STATUS_OK
;
403 status
= LTTNG_ACTION_STATUS_UNSET
;