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