Build fix: missing stdio.h include in signal-helper.hpp
[lttng-tools.git] / src / common / actions / snapshot-session.cpp
CommitLineData
757c48a2
SM
1/*
2 * Copyright (C) 2019 Simon Marchi <simon.marchi@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
c9e313bc
SM
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>
d35c7a38 14#include <inttypes.h>
c9e313bc
SM
15#include <lttng/action/action-internal.hpp>
16#include <lttng/action/rate-policy-internal.hpp>
7f4d5b07 17#include <lttng/action/rate-policy.h>
c9e313bc 18#include <lttng/action/snapshot-session-internal.hpp>
757c48a2 19#include <lttng/action/snapshot-session.h>
c9e313bc 20#include <lttng/snapshot-internal.hpp>
d35c7a38 21#include <lttng/snapshot.h>
757c48a2
SM
22
23#define IS_SNAPSHOT_SESSION_ACTION(action) \
17182cfd 24 (lttng_action_get_type(action) == LTTNG_ACTION_TYPE_SNAPSHOT_SESSION)
757c48a2 25
f1494934 26namespace {
757c48a2
SM
27struct lttng_action_snapshot_session {
28 struct lttng_action parent;
29
30 /* Owned by this. */
31 char *session_name;
32
33 /*
34 * When non-NULL, use this custom output when taking the snapshot,
35 * rather than the session's registered snapshot output.
36 *
37 * Owned by this.
38 */
39 struct lttng_snapshot_output *output;
7f4d5b07 40 struct lttng_rate_policy *policy;
757c48a2
SM
41};
42
43struct 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;
7f4d5b07 47 uint32_t rate_policy_len;
757c48a2
SM
48
49 /*
50 * Variable data (all strings are null-terminated):
51 *
52 * - session name string
53 * - snapshot output object
d35c7a38 54 * - policy object
757c48a2
SM
55 */
56 char data[];
57} LTTNG_PACKED;
f1494934 58} /* namespace */
757c48a2 59
7f4d5b07
JR
60static const struct lttng_rate_policy *
61lttng_action_snapshot_session_internal_get_rate_policy(
2d57482c
JR
62 const struct lttng_action *action);
63
757c48a2
SM
64static struct lttng_action_snapshot_session *
65action_snapshot_session_from_action(struct lttng_action *action)
66{
a0377dfe 67 LTTNG_ASSERT(action);
757c48a2 68
0114db0e
JG
69 return lttng::utils::container_of(
70 action, &lttng_action_snapshot_session::parent);
757c48a2
SM
71}
72
73static const struct lttng_action_snapshot_session *
74action_snapshot_session_from_action_const(const struct lttng_action *action)
75{
a0377dfe 76 LTTNG_ASSERT(action);
757c48a2 77
0114db0e
JG
78 return lttng::utils::container_of(
79 action, &lttng_action_snapshot_session::parent);
757c48a2
SM
80}
81
82static bool lttng_action_snapshot_session_validate(struct lttng_action *action)
83{
84 bool valid = false;
85 struct lttng_action_snapshot_session *action_snapshot_session;
86
87 if (!action) {
88 goto end;
89 }
90
91 action_snapshot_session = action_snapshot_session_from_action(action);
92
93 /* A non-empty session name is mandatory. */
94 if (!action_snapshot_session->session_name ||
95 strlen(action_snapshot_session->session_name) == 0) {
96 goto end;
97 }
98
99 if (action_snapshot_session->output &&
100 !lttng_snapshot_output_validate(action_snapshot_session->output)) {
101 goto end;
102 }
103
104 valid = true;
105end:
106 return valid;
107}
108
109static bool lttng_action_snapshot_session_is_equal(
110 const struct lttng_action *_a, const struct lttng_action *_b)
111{
112 bool is_equal = false;
113 const struct lttng_action_snapshot_session *a, *b;
114
115 a = action_snapshot_session_from_action_const(_a);
116 b = action_snapshot_session_from_action_const(_b);
117
118 /* Action is not valid if this is not true. */
a0377dfe
FD
119 LTTNG_ASSERT(a->session_name);
120 LTTNG_ASSERT(b->session_name);
757c48a2
SM
121 if (strcmp(a->session_name, b->session_name)) {
122 goto end;
123 }
124
125 if (a->output && b->output &&
126 !lttng_snapshot_output_is_equal(a->output, b->output)) {
127 goto end;
128 } else if (!!a->output != !!b->output) {
129 goto end;
130 }
131
7f4d5b07 132 is_equal = lttng_rate_policy_is_equal(a->policy, b->policy);
757c48a2
SM
133end:
134 return is_equal;
135}
136
0c51e8f3 137static size_t serialize_strlen(const char *str)
757c48a2 138{
0c51e8f3 139 return str ? strlen(str) + 1 : 0;
757c48a2
SM
140}
141
142static int lttng_action_snapshot_session_serialize(
143 struct lttng_action *action, struct lttng_payload *payload)
144{
145 struct lttng_action_snapshot_session *action_snapshot_session;
146 struct lttng_action_snapshot_session_comm comm = {};
147 int ret;
148 size_t size_before_comm;
149
a0377dfe
FD
150 LTTNG_ASSERT(action);
151 LTTNG_ASSERT(payload);
757c48a2
SM
152
153 size_before_comm = payload->buffer.size;
757c48a2
SM
154
155 action_snapshot_session = action_snapshot_session_from_action(action);
156 comm.session_name_len =
157 serialize_strlen(action_snapshot_session->session_name);
158
159 /* Add header. */
160 ret = lttng_dynamic_buffer_append(
161 &payload->buffer, &comm, sizeof(comm));
162 if (ret) {
163 goto end;
164 }
165
a0377dfe 166 LTTNG_ASSERT(action_snapshot_session->session_name);
757c48a2
SM
167 DBG("Serializing snapshot session action: session-name: %s",
168 action_snapshot_session->session_name);
169
170 /* Add session name. */
171 ret = lttng_dynamic_buffer_append(&payload->buffer,
172 action_snapshot_session->session_name,
173 comm.session_name_len);
174 if (ret) {
175 goto end;
176 }
177
178 /* Serialize the snapshot output object, if any. */
179 if (action_snapshot_session->output) {
180 const size_t size_before_output = payload->buffer.size;
181 struct lttng_action_snapshot_session_comm *comm_in_payload;
182
183 ret = lttng_snapshot_output_serialize(
184 action_snapshot_session->output,
185 payload);
186 if (ret) {
187 goto end;
188 }
189
757c48a2
SM
190 comm_in_payload = (typeof(comm_in_payload))(
191 payload->buffer.data + size_before_comm);
d35c7a38 192 /* Adjust action length in header. */
757c48a2
SM
193 comm_in_payload->snapshot_output_len =
194 payload->buffer.size - size_before_output;
195 }
196
7f4d5b07 197 /* Serialize the rate policy. */
d35c7a38
JR
198 {
199 const size_t size_before_output = payload->buffer.size;
200 struct lttng_action_snapshot_session_comm *comm_in_payload;
201
7f4d5b07 202 ret = lttng_rate_policy_serialize(
d35c7a38
JR
203 action_snapshot_session->policy, payload);
204 if (ret) {
205 ret = -1;
206 goto end;
207 }
208
209 comm_in_payload = (typeof(comm_in_payload))(
210 payload->buffer.data + size_before_comm);
7f4d5b07
JR
211 /* Adjust rate policy length in header. */
212 comm_in_payload->rate_policy_len =
d35c7a38
JR
213 payload->buffer.size - size_before_output;
214 }
215
757c48a2
SM
216end:
217 return ret;
218}
219
220static void lttng_action_snapshot_session_destroy(struct lttng_action *action)
221{
222 struct lttng_action_snapshot_session *action_snapshot_session;
223
224 if (!action) {
225 goto end;
226 }
227
228 action_snapshot_session = action_snapshot_session_from_action(action);
229
230 free(action_snapshot_session->session_name);
231 lttng_snapshot_output_destroy(action_snapshot_session->output);
7f4d5b07 232 lttng_rate_policy_destroy(action_snapshot_session->policy);
757c48a2
SM
233 free(action_snapshot_session);
234
235end:
236 return;
237}
238
239ssize_t lttng_action_snapshot_session_create_from_payload(
240 struct lttng_payload_view *view,
241 struct lttng_action **p_action)
242{
243 ssize_t consumed_len;
757c48a2
SM
244 const char *variable_data;
245 struct lttng_action *action;
246 enum lttng_action_status status;
247 struct lttng_snapshot_output *snapshot_output = NULL;
7f4d5b07 248 struct lttng_rate_policy *policy = NULL;
3e6e0df2
JG
249 const struct lttng_action_snapshot_session_comm *comm;
250 const struct lttng_payload_view snapshot_session_comm_view =
251 lttng_payload_view_from_view(
252 view, 0, sizeof(*comm));
757c48a2
SM
253
254 action = lttng_action_snapshot_session_create();
255 if (!action) {
256 goto error;
257 }
258
3e6e0df2
JG
259 if (!lttng_payload_view_is_valid(&snapshot_session_comm_view)) {
260 /* Payload not large enough to contain the header. */
261 goto error;
262 }
263
264 comm = (typeof(comm)) snapshot_session_comm_view.buffer.data;
757c48a2
SM
265 variable_data = (const char *) &comm->data;
266
267 consumed_len = sizeof(struct lttng_action_snapshot_session_comm);
268
269 if (!lttng_buffer_view_contains_string(
270 &view->buffer, variable_data, comm->session_name_len)) {
271 goto error;
272 }
273
274 status = lttng_action_snapshot_session_set_session_name(
275 action, variable_data);
276 if (status != LTTNG_ACTION_STATUS_OK) {
277 goto error;
278 }
279
280 variable_data += comm->session_name_len;
281 consumed_len += comm->session_name_len;
282
283 /* If there is a snapshot output object, deserialize it. */
284 if (comm->snapshot_output_len > 0) {
285 ssize_t snapshot_output_consumed_len;
286 enum lttng_action_status action_status;
287 struct lttng_payload_view snapshot_output_buffer_view =
288 lttng_payload_view_from_view(view, consumed_len,
289 comm->snapshot_output_len);
290
3e6e0df2 291 if (!lttng_payload_view_is_valid(&snapshot_output_buffer_view)) {
0c51e8f3 292 ERR("Failed to create buffer view for snapshot output.");
757c48a2
SM
293 goto error;
294 }
295
296 snapshot_output_consumed_len =
297 lttng_snapshot_output_create_from_payload(
298 &snapshot_output_buffer_view,
299 &snapshot_output);
300 if (snapshot_output_consumed_len != comm->snapshot_output_len) {
0c51e8f3 301 ERR("Failed to deserialize snapshot output object: "
757c48a2
SM
302 "consumed-len: %zd, expected-len: %" PRIu32,
303 snapshot_output_consumed_len,
304 comm->snapshot_output_len);
305 goto error;
306 }
307
308 action_status = lttng_action_snapshot_session_set_output(
309 action, snapshot_output);
310 if (action_status != LTTNG_ACTION_STATUS_OK) {
311 goto error;
312 }
313
314 /* Ownership has been transferred to the action. */
315 snapshot_output = NULL;
316 }
317
318 variable_data += comm->snapshot_output_len;
319 consumed_len += comm->snapshot_output_len;
d35c7a38 320
7f4d5b07
JR
321 /* Rate policy. */
322 if (comm->rate_policy_len <= 0) {
323 ERR("Rate policy should be present.");
d35c7a38
JR
324 goto error;
325 }
326 {
7f4d5b07 327 ssize_t rate_policy_consumed_len;
d35c7a38
JR
328 struct lttng_payload_view policy_view =
329 lttng_payload_view_from_view(view, consumed_len,
7f4d5b07 330 comm->rate_policy_len);
d35c7a38
JR
331
332 if (!lttng_payload_view_is_valid(&policy_view)) {
7f4d5b07 333 ERR("Failed to create buffer view for rate policy.");
d35c7a38
JR
334 goto error;
335 }
336
7f4d5b07
JR
337 rate_policy_consumed_len =
338 lttng_rate_policy_create_from_payload(
d35c7a38 339 &policy_view, &policy);
7f4d5b07 340 if (rate_policy_consumed_len < 0) {
d35c7a38
JR
341 goto error;
342 }
343
7f4d5b07
JR
344 if (rate_policy_consumed_len != comm->rate_policy_len) {
345 ERR("Failed to deserialize rate policy object: "
d35c7a38 346 "consumed-len: %zd, expected-len: %" PRIu32,
7f4d5b07
JR
347 rate_policy_consumed_len,
348 comm->rate_policy_len);
d35c7a38
JR
349 goto error;
350 }
351
7f4d5b07 352 status = lttng_action_snapshot_session_set_rate_policy(
d35c7a38
JR
353 action, policy);
354 if (status != LTTNG_ACTION_STATUS_OK) {
355 goto error;
356 }
357 }
358
7f4d5b07
JR
359 variable_data += comm->rate_policy_len;
360 consumed_len += comm->rate_policy_len;
d35c7a38 361
757c48a2
SM
362 *p_action = action;
363 action = NULL;
364
365 goto end;
366
367error:
368 consumed_len = -1;
369
370end:
7f4d5b07 371 lttng_rate_policy_destroy(policy);
757c48a2
SM
372 lttng_action_snapshot_session_destroy(action);
373 lttng_snapshot_output_destroy(snapshot_output);
374
375 return consumed_len;
376}
377
6a751b95
JR
378static enum lttng_error_code lttng_action_snapshot_session_mi_serialize(
379 const struct lttng_action *action, struct mi_writer *writer)
380{
381 int ret;
382 enum lttng_error_code ret_code;
383 enum lttng_action_status status;
384 const char *session_name = NULL;
385 const struct lttng_snapshot_output *output = NULL;
386 const struct lttng_rate_policy *policy = NULL;
387
a0377dfe
FD
388 LTTNG_ASSERT(action);
389 LTTNG_ASSERT(IS_SNAPSHOT_SESSION_ACTION(action));
6a751b95
JR
390
391 status = lttng_action_snapshot_session_get_session_name(
392 action, &session_name);
a0377dfe
FD
393 LTTNG_ASSERT(status == LTTNG_ACTION_STATUS_OK);
394 LTTNG_ASSERT(session_name != NULL);
6a751b95
JR
395
396 status = lttng_action_snapshot_session_get_rate_policy(action, &policy);
a0377dfe
FD
397 LTTNG_ASSERT(status == LTTNG_ACTION_STATUS_OK);
398 LTTNG_ASSERT(policy != NULL);
6a751b95
JR
399
400 /* Open action snapshot session element. */
401 ret = mi_lttng_writer_open_element(
402 writer, mi_lttng_element_action_snapshot_session);
403 if (ret) {
404 goto mi_error;
405 }
406
407 /* Session name. */
408 ret = mi_lttng_writer_write_element_string(
409 writer, mi_lttng_element_session_name, session_name);
410 if (ret) {
411 goto mi_error;
412 }
413
414 /* Output if any. */
415 status = lttng_action_snapshot_session_get_output(action, &output);
416 if (status == LTTNG_ACTION_STATUS_OK) {
a0377dfe 417 LTTNG_ASSERT(output != NULL);
6a751b95
JR
418 ret_code = lttng_snapshot_output_mi_serialize(output, writer);
419 if (ret_code != LTTNG_OK) {
420 goto end;
421 }
422 } else if (status != LTTNG_ACTION_STATUS_UNSET) {
423 /* This should not happen at this point. */
424 abort();
425 }
426
427 /* Rate policy. */
428 ret_code = lttng_rate_policy_mi_serialize(policy, writer);
429 if (ret_code != LTTNG_OK) {
430 goto end;
431 }
432
433 /* Close action_snapshot_session element. */
434 ret = mi_lttng_writer_close_element(writer);
435 if (ret) {
436 goto mi_error;
437 }
438
439 ret_code = LTTNG_OK;
440 goto end;
441
442mi_error:
443 ret_code = LTTNG_ERR_MI_IO_FAIL;
444end:
445 return ret_code;
446}
447
757c48a2
SM
448struct lttng_action *lttng_action_snapshot_session_create(void)
449{
64803277 450 struct lttng_action_snapshot_session *action_snapshot = NULL;
7f4d5b07 451 struct lttng_rate_policy *policy = NULL;
d35c7a38
JR
452 enum lttng_action_status status;
453
7f4d5b07
JR
454 /* Create a every N = 1 rate policy. */
455 policy = lttng_rate_policy_every_n_create(1);
d35c7a38
JR
456 if (!policy) {
457 goto end;
458 }
757c48a2 459
64803277
SM
460 action_snapshot = zmalloc<lttng_action_snapshot_session>();
461 if (!action_snapshot) {
757c48a2
SM
462 goto end;
463 }
464
64803277
SM
465 lttng_action_init(&action_snapshot->parent,
466 LTTNG_ACTION_TYPE_SNAPSHOT_SESSION,
757c48a2
SM
467 lttng_action_snapshot_session_validate,
468 lttng_action_snapshot_session_serialize,
469 lttng_action_snapshot_session_is_equal,
2d57482c 470 lttng_action_snapshot_session_destroy,
588c4b0d 471 lttng_action_snapshot_session_internal_get_rate_policy,
6a751b95
JR
472 lttng_action_generic_add_error_query_results,
473 lttng_action_snapshot_session_mi_serialize);
757c48a2 474
64803277
SM
475 status = lttng_action_snapshot_session_set_rate_policy(
476 &action_snapshot->parent, policy);
d35c7a38 477 if (status != LTTNG_ACTION_STATUS_OK) {
64803277
SM
478 lttng_action_destroy(&action_snapshot->parent);
479 action_snapshot = NULL;
d35c7a38
JR
480 goto end;
481 }
482
757c48a2 483end:
7f4d5b07 484 lttng_rate_policy_destroy(policy);
64803277 485 return action_snapshot ? &action_snapshot->parent : nullptr;
757c48a2
SM
486}
487
488enum lttng_action_status lttng_action_snapshot_session_set_session_name(
489 struct lttng_action *action, const char *session_name)
490{
491 struct lttng_action_snapshot_session *action_snapshot_session;
492 enum lttng_action_status status;
493
494 if (!action || !IS_SNAPSHOT_SESSION_ACTION(action) || !session_name ||
495 strlen(session_name) == 0) {
496 status = LTTNG_ACTION_STATUS_INVALID;
497 goto end;
498 }
499
500 action_snapshot_session = action_snapshot_session_from_action(action);
501
502 free(action_snapshot_session->session_name);
503
504 action_snapshot_session->session_name = strdup(session_name);
505 if (!action_snapshot_session->session_name) {
506 status = LTTNG_ACTION_STATUS_ERROR;
507 goto end;
508 }
509
510 status = LTTNG_ACTION_STATUS_OK;
511end:
512 return status;
513}
514
515enum lttng_action_status lttng_action_snapshot_session_get_session_name(
516 const struct lttng_action *action, const char **session_name)
517{
518 const struct lttng_action_snapshot_session *action_snapshot_session;
519 enum lttng_action_status status;
520
521 if (!action || !IS_SNAPSHOT_SESSION_ACTION(action) || !session_name) {
522 status = LTTNG_ACTION_STATUS_INVALID;
523 goto end;
524 }
525
526 action_snapshot_session = action_snapshot_session_from_action_const(action);
527
528 if (action_snapshot_session->session_name) {
529 *session_name = action_snapshot_session->session_name;
530 status = LTTNG_ACTION_STATUS_OK;
531 } else {
532 status = LTTNG_ACTION_STATUS_UNSET;
533 }
534
535end:
536
537 return status;
538}
539
540enum lttng_action_status lttng_action_snapshot_session_set_output(
541 struct lttng_action *action,
542 struct lttng_snapshot_output *output)
543{
544 struct lttng_action_snapshot_session *action_snapshot_session;
545 enum lttng_action_status status;
546
547 if (!action || !IS_SNAPSHOT_SESSION_ACTION(action) || !output) {
548 status = LTTNG_ACTION_STATUS_INVALID;
549 goto end;
550 }
551
552 action_snapshot_session = action_snapshot_session_from_action(action);
553
554 lttng_snapshot_output_destroy(action_snapshot_session->output);
555 action_snapshot_session->output = output;
556
557 status = LTTNG_ACTION_STATUS_OK;
558
559end:
560 return status;
561}
562
563enum lttng_action_status lttng_action_snapshot_session_get_output(
564 const struct lttng_action *action,
565 const struct lttng_snapshot_output **output)
566{
567 const struct lttng_action_snapshot_session *action_snapshot_session;
568 enum lttng_action_status status;
569
570 if (!action || !IS_SNAPSHOT_SESSION_ACTION(action)|| !output) {
571 status = LTTNG_ACTION_STATUS_INVALID;
572 goto end;
573 }
574
575 action_snapshot_session = action_snapshot_session_from_action_const(action);
576
577 if (action_snapshot_session->output) {
578 *output = action_snapshot_session->output;
579 status = LTTNG_ACTION_STATUS_OK;
580 } else {
581 status = LTTNG_ACTION_STATUS_UNSET;
582 }
583
584end:
585 return status;
586}
d35c7a38 587
7f4d5b07 588enum lttng_action_status lttng_action_snapshot_session_set_rate_policy(
d35c7a38 589 struct lttng_action *action,
7f4d5b07 590 const struct lttng_rate_policy *policy)
d35c7a38
JR
591{
592 enum lttng_action_status status;
593 struct lttng_action_snapshot_session *snapshot_session_action;
7f4d5b07 594 struct lttng_rate_policy *copy = NULL;
d35c7a38
JR
595
596 if (!action || !policy || !IS_SNAPSHOT_SESSION_ACTION(action)) {
597 status = LTTNG_ACTION_STATUS_INVALID;
598 goto end;
599 }
600
7f4d5b07 601 copy = lttng_rate_policy_copy(policy);
d35c7a38
JR
602 if (!copy) {
603 status = LTTNG_ACTION_STATUS_ERROR;
604 goto end;
605 }
606
607 snapshot_session_action = action_snapshot_session_from_action(action);
608
7f4d5b07
JR
609 /* Free the previous rate policy .*/
610 lttng_rate_policy_destroy(snapshot_session_action->policy);
d35c7a38
JR
611
612 /* Assign the policy. */
613 snapshot_session_action->policy = copy;
614 status = LTTNG_ACTION_STATUS_OK;
615 copy = NULL;
616
617end:
7f4d5b07 618 lttng_rate_policy_destroy(copy);
d35c7a38
JR
619 return status;
620}
621
7f4d5b07 622enum lttng_action_status lttng_action_snapshot_session_get_rate_policy(
d35c7a38 623 const struct lttng_action *action,
7f4d5b07 624 const struct lttng_rate_policy **policy)
d35c7a38
JR
625{
626 enum lttng_action_status status;
627 const struct lttng_action_snapshot_session *snapshot_session_action;
628
629 if (!action || !policy || !IS_SNAPSHOT_SESSION_ACTION(action)) {
630 status = LTTNG_ACTION_STATUS_INVALID;
631 goto end;
632 }
633
634 snapshot_session_action =
635 action_snapshot_session_from_action_const(action);
636
637 *policy = snapshot_session_action->policy;
638 status = LTTNG_ACTION_STATUS_OK;
639end:
640 return status;
641}
2d57482c 642
7f4d5b07
JR
643static const struct lttng_rate_policy *
644lttng_action_snapshot_session_internal_get_rate_policy(
2d57482c
JR
645 const struct lttng_action *action)
646{
647 const struct lttng_action_snapshot_session *_action;
648 _action = action_snapshot_session_from_action_const(action);
649
650 return _action->policy;
651}
This page took 0.069339 seconds and 4 git commands to generate.