5d01784958de3eed0bd07d1119d51b9c73204142
[lttng-tools.git] / src / common / actions / snapshot-session.c
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>
11 #include <common/payload-view.h>
12 #include <common/payload.h>
13 #include <common/snapshot.h>
14 #include <inttypes.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>
22
23 #define IS_SNAPSHOT_SESSION_ACTION(action) \
24 (lttng_action_get_type(action) == LTTNG_ACTION_TYPE_SNAPSHOT_SESSION)
25
26 struct lttng_action_snapshot_session {
27 struct lttng_action parent;
28
29 /* Owned by this. */
30 char *session_name;
31
32 /*
33 * When non-NULL, use this custom output when taking the snapshot,
34 * rather than the session's registered snapshot output.
35 *
36 * Owned by this.
37 */
38 struct lttng_snapshot_output *output;
39 struct lttng_firing_policy *policy;
40 };
41
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;
47
48 /*
49 * Variable data (all strings are null-terminated):
50 *
51 * - session name string
52 * - snapshot output object
53 * - policy object
54 */
55 char data[];
56 } LTTNG_PACKED;
57
58 static const struct lttng_firing_policy *
59 lttng_action_snapshot_session_internal_get_firing_policy(
60 const struct lttng_action *action);
61
62 static struct lttng_action_snapshot_session *
63 action_snapshot_session_from_action(struct lttng_action *action)
64 {
65 assert(action);
66
67 return container_of(
68 action, struct lttng_action_snapshot_session, parent);
69 }
70
71 static const struct lttng_action_snapshot_session *
72 action_snapshot_session_from_action_const(const struct lttng_action *action)
73 {
74 assert(action);
75
76 return container_of(
77 action, struct lttng_action_snapshot_session, parent);
78 }
79
80 static bool lttng_action_snapshot_session_validate(struct lttng_action *action)
81 {
82 bool valid = false;
83 struct lttng_action_snapshot_session *action_snapshot_session;
84
85 if (!action) {
86 goto end;
87 }
88
89 action_snapshot_session = action_snapshot_session_from_action(action);
90
91 /* A non-empty session name is mandatory. */
92 if (!action_snapshot_session->session_name ||
93 strlen(action_snapshot_session->session_name) == 0) {
94 goto end;
95 }
96
97 if (action_snapshot_session->output &&
98 !lttng_snapshot_output_validate(action_snapshot_session->output)) {
99 goto end;
100 }
101
102 valid = true;
103 end:
104 return valid;
105 }
106
107 static bool lttng_action_snapshot_session_is_equal(
108 const struct lttng_action *_a, const struct lttng_action *_b)
109 {
110 bool is_equal = false;
111 const struct lttng_action_snapshot_session *a, *b;
112
113 a = action_snapshot_session_from_action_const(_a);
114 b = action_snapshot_session_from_action_const(_b);
115
116 /* Action is not valid if this is not true. */
117 assert(a->session_name);
118 assert(b->session_name);
119 if (strcmp(a->session_name, b->session_name)) {
120 goto end;
121 }
122
123 if (a->output && b->output &&
124 !lttng_snapshot_output_is_equal(a->output, b->output)) {
125 goto end;
126 } else if (!!a->output != !!b->output) {
127 goto end;
128 }
129
130 is_equal = lttng_firing_policy_is_equal(a->policy, b->policy);
131 end:
132 return is_equal;
133 }
134
135 static size_t serialize_strlen(const char *str)
136 {
137 return str ? strlen(str) + 1 : 0;
138 }
139
140 static int lttng_action_snapshot_session_serialize(
141 struct lttng_action *action, struct lttng_payload *payload)
142 {
143 struct lttng_action_snapshot_session *action_snapshot_session;
144 struct lttng_action_snapshot_session_comm comm = {};
145 int ret;
146 size_t size_before_comm;
147
148 assert(action);
149 assert(payload);
150
151 size_before_comm = payload->buffer.size;
152
153 action_snapshot_session = action_snapshot_session_from_action(action);
154 comm.session_name_len =
155 serialize_strlen(action_snapshot_session->session_name);
156
157 /* Add header. */
158 ret = lttng_dynamic_buffer_append(
159 &payload->buffer, &comm, sizeof(comm));
160 if (ret) {
161 goto end;
162 }
163
164 assert(action_snapshot_session->session_name);
165 DBG("Serializing snapshot session action: session-name: %s",
166 action_snapshot_session->session_name);
167
168 /* Add session name. */
169 ret = lttng_dynamic_buffer_append(&payload->buffer,
170 action_snapshot_session->session_name,
171 comm.session_name_len);
172 if (ret) {
173 goto end;
174 }
175
176 /* Serialize the snapshot output object, if any. */
177 if (action_snapshot_session->output) {
178 const size_t size_before_output = payload->buffer.size;
179 struct lttng_action_snapshot_session_comm *comm_in_payload;
180
181 ret = lttng_snapshot_output_serialize(
182 action_snapshot_session->output,
183 payload);
184 if (ret) {
185 goto end;
186 }
187
188 comm_in_payload = (typeof(comm_in_payload))(
189 payload->buffer.data + size_before_comm);
190 /* Adjust action length in header. */
191 comm_in_payload->snapshot_output_len =
192 payload->buffer.size - size_before_output;
193 }
194
195 /* Serialize the firing policy. */
196 {
197 const size_t size_before_output = payload->buffer.size;
198 struct lttng_action_snapshot_session_comm *comm_in_payload;
199
200 ret = lttng_firing_policy_serialize(
201 action_snapshot_session->policy, payload);
202 if (ret) {
203 ret = -1;
204 goto end;
205 }
206
207 comm_in_payload = (typeof(comm_in_payload))(
208 payload->buffer.data + size_before_comm);
209 /* Adjust firing policy length in header. */
210 comm_in_payload->firing_policy_len =
211 payload->buffer.size - size_before_output;
212 }
213
214 end:
215 return ret;
216 }
217
218 static void lttng_action_snapshot_session_destroy(struct lttng_action *action)
219 {
220 struct lttng_action_snapshot_session *action_snapshot_session;
221
222 if (!action) {
223 goto end;
224 }
225
226 action_snapshot_session = action_snapshot_session_from_action(action);
227
228 free(action_snapshot_session->session_name);
229 lttng_snapshot_output_destroy(action_snapshot_session->output);
230 lttng_firing_policy_destroy(action_snapshot_session->policy);
231 free(action_snapshot_session);
232
233 end:
234 return;
235 }
236
237 ssize_t lttng_action_snapshot_session_create_from_payload(
238 struct lttng_payload_view *view,
239 struct lttng_action **p_action)
240 {
241 ssize_t consumed_len;
242 const char *variable_data;
243 struct lttng_action *action;
244 enum lttng_action_status status;
245 struct lttng_snapshot_output *snapshot_output = NULL;
246 struct lttng_firing_policy *policy = NULL;
247 const struct lttng_action_snapshot_session_comm *comm;
248 const struct lttng_payload_view snapshot_session_comm_view =
249 lttng_payload_view_from_view(
250 view, 0, sizeof(*comm));
251
252 action = lttng_action_snapshot_session_create();
253 if (!action) {
254 goto error;
255 }
256
257 if (!lttng_payload_view_is_valid(&snapshot_session_comm_view)) {
258 /* Payload not large enough to contain the header. */
259 goto error;
260 }
261
262 comm = (typeof(comm)) snapshot_session_comm_view.buffer.data;
263 variable_data = (const char *) &comm->data;
264
265 consumed_len = sizeof(struct lttng_action_snapshot_session_comm);
266
267 if (!lttng_buffer_view_contains_string(
268 &view->buffer, variable_data, comm->session_name_len)) {
269 goto error;
270 }
271
272 status = lttng_action_snapshot_session_set_session_name(
273 action, variable_data);
274 if (status != LTTNG_ACTION_STATUS_OK) {
275 goto error;
276 }
277
278 variable_data += comm->session_name_len;
279 consumed_len += comm->session_name_len;
280
281 /* If there is a snapshot output object, deserialize it. */
282 if (comm->snapshot_output_len > 0) {
283 ssize_t snapshot_output_consumed_len;
284 enum lttng_action_status action_status;
285 struct lttng_payload_view snapshot_output_buffer_view =
286 lttng_payload_view_from_view(view, consumed_len,
287 comm->snapshot_output_len);
288
289 if (!lttng_payload_view_is_valid(&snapshot_output_buffer_view)) {
290 ERR("Failed to create buffer view for snapshot output.");
291 goto error;
292 }
293
294 snapshot_output_consumed_len =
295 lttng_snapshot_output_create_from_payload(
296 &snapshot_output_buffer_view,
297 &snapshot_output);
298 if (snapshot_output_consumed_len != comm->snapshot_output_len) {
299 ERR("Failed to deserialize snapshot output object: "
300 "consumed-len: %zd, expected-len: %" PRIu32,
301 snapshot_output_consumed_len,
302 comm->snapshot_output_len);
303 goto error;
304 }
305
306 action_status = lttng_action_snapshot_session_set_output(
307 action, snapshot_output);
308 if (action_status != LTTNG_ACTION_STATUS_OK) {
309 goto error;
310 }
311
312 /* Ownership has been transferred to the action. */
313 snapshot_output = NULL;
314 }
315
316 variable_data += comm->snapshot_output_len;
317 consumed_len += comm->snapshot_output_len;
318
319 /* Firing policy. */
320 if (comm->firing_policy_len <= 0) {
321 ERR("Firing policy should be present.");
322 goto error;
323 }
324 {
325 ssize_t firing_policy_consumed_len;
326 struct lttng_payload_view policy_view =
327 lttng_payload_view_from_view(view, consumed_len,
328 comm->firing_policy_len);
329
330 if (!lttng_payload_view_is_valid(&policy_view)) {
331 ERR("Failed to create buffer view for firing policy.");
332 goto error;
333 }
334
335 firing_policy_consumed_len =
336 lttng_firing_policy_create_from_payload(
337 &policy_view, &policy);
338 if (firing_policy_consumed_len < 0) {
339 goto error;
340 }
341
342 if (firing_policy_consumed_len != comm->firing_policy_len) {
343 ERR("Failed to deserialize firing policy object: "
344 "consumed-len: %zd, expected-len: %" PRIu32,
345 firing_policy_consumed_len,
346 comm->firing_policy_len);
347 goto error;
348 }
349
350 status = lttng_action_snapshot_session_set_firing_policy(
351 action, policy);
352 if (status != LTTNG_ACTION_STATUS_OK) {
353 goto error;
354 }
355 }
356
357 variable_data += comm->firing_policy_len;
358 consumed_len += comm->firing_policy_len;
359
360 *p_action = action;
361 action = NULL;
362
363 goto end;
364
365 error:
366 consumed_len = -1;
367
368 end:
369 lttng_firing_policy_destroy(policy);
370 lttng_action_snapshot_session_destroy(action);
371 lttng_snapshot_output_destroy(snapshot_output);
372
373 return consumed_len;
374 }
375
376 struct lttng_action *lttng_action_snapshot_session_create(void)
377 {
378 struct lttng_action *action = NULL;
379 struct lttng_firing_policy *policy = NULL;
380 enum lttng_action_status status;
381
382 /* Create a every N = 1 firing policy. */
383 policy = lttng_firing_policy_every_n_create(1);
384 if (!policy) {
385 goto end;
386 }
387
388 action = zmalloc(sizeof(struct lttng_action_snapshot_session));
389 if (!action) {
390 goto end;
391 }
392
393 lttng_action_init(action, LTTNG_ACTION_TYPE_SNAPSHOT_SESSION,
394 lttng_action_snapshot_session_validate,
395 lttng_action_snapshot_session_serialize,
396 lttng_action_snapshot_session_is_equal,
397 lttng_action_snapshot_session_destroy,
398 lttng_action_snapshot_session_internal_get_firing_policy);
399
400 status = lttng_action_snapshot_session_set_firing_policy(
401 action, policy);
402 if (status != LTTNG_ACTION_STATUS_OK) {
403 free(action);
404 action = NULL;
405 goto end;
406 }
407
408 end:
409 lttng_firing_policy_destroy(policy);
410 return action;
411 }
412
413 enum lttng_action_status lttng_action_snapshot_session_set_session_name(
414 struct lttng_action *action, const char *session_name)
415 {
416 struct lttng_action_snapshot_session *action_snapshot_session;
417 enum lttng_action_status status;
418
419 if (!action || !IS_SNAPSHOT_SESSION_ACTION(action) || !session_name ||
420 strlen(session_name) == 0) {
421 status = LTTNG_ACTION_STATUS_INVALID;
422 goto end;
423 }
424
425 action_snapshot_session = action_snapshot_session_from_action(action);
426
427 free(action_snapshot_session->session_name);
428
429 action_snapshot_session->session_name = strdup(session_name);
430 if (!action_snapshot_session->session_name) {
431 status = LTTNG_ACTION_STATUS_ERROR;
432 goto end;
433 }
434
435 status = LTTNG_ACTION_STATUS_OK;
436 end:
437 return status;
438 }
439
440 enum lttng_action_status lttng_action_snapshot_session_get_session_name(
441 const struct lttng_action *action, const char **session_name)
442 {
443 const struct lttng_action_snapshot_session *action_snapshot_session;
444 enum lttng_action_status status;
445
446 if (!action || !IS_SNAPSHOT_SESSION_ACTION(action) || !session_name) {
447 status = LTTNG_ACTION_STATUS_INVALID;
448 goto end;
449 }
450
451 action_snapshot_session = action_snapshot_session_from_action_const(action);
452
453 if (action_snapshot_session->session_name) {
454 *session_name = action_snapshot_session->session_name;
455 status = LTTNG_ACTION_STATUS_OK;
456 } else {
457 status = LTTNG_ACTION_STATUS_UNSET;
458 }
459
460 end:
461
462 return status;
463 }
464
465 enum lttng_action_status lttng_action_snapshot_session_set_output(
466 struct lttng_action *action,
467 struct lttng_snapshot_output *output)
468 {
469 struct lttng_action_snapshot_session *action_snapshot_session;
470 enum lttng_action_status status;
471
472 if (!action || !IS_SNAPSHOT_SESSION_ACTION(action) || !output) {
473 status = LTTNG_ACTION_STATUS_INVALID;
474 goto end;
475 }
476
477 action_snapshot_session = action_snapshot_session_from_action(action);
478
479 lttng_snapshot_output_destroy(action_snapshot_session->output);
480 action_snapshot_session->output = output;
481
482 status = LTTNG_ACTION_STATUS_OK;
483
484 end:
485 return status;
486 }
487
488 enum lttng_action_status lttng_action_snapshot_session_get_output(
489 const struct lttng_action *action,
490 const struct lttng_snapshot_output **output)
491 {
492 const struct lttng_action_snapshot_session *action_snapshot_session;
493 enum lttng_action_status status;
494
495 if (!action || !IS_SNAPSHOT_SESSION_ACTION(action)|| !output) {
496 status = LTTNG_ACTION_STATUS_INVALID;
497 goto end;
498 }
499
500 action_snapshot_session = action_snapshot_session_from_action_const(action);
501
502 if (action_snapshot_session->output) {
503 *output = action_snapshot_session->output;
504 status = LTTNG_ACTION_STATUS_OK;
505 } else {
506 status = LTTNG_ACTION_STATUS_UNSET;
507 }
508
509 end:
510 return status;
511 }
512
513 enum lttng_action_status lttng_action_snapshot_session_set_firing_policy(
514 struct lttng_action *action,
515 const struct lttng_firing_policy *policy)
516 {
517 enum lttng_action_status status;
518 struct lttng_action_snapshot_session *snapshot_session_action;
519 struct lttng_firing_policy *copy = NULL;
520
521 if (!action || !policy || !IS_SNAPSHOT_SESSION_ACTION(action)) {
522 status = LTTNG_ACTION_STATUS_INVALID;
523 goto end;
524 }
525
526 copy = lttng_firing_policy_copy(policy);
527 if (!copy) {
528 status = LTTNG_ACTION_STATUS_ERROR;
529 goto end;
530 }
531
532 snapshot_session_action = action_snapshot_session_from_action(action);
533
534 /* Free the previous firing policy .*/
535 lttng_firing_policy_destroy(snapshot_session_action->policy);
536
537 /* Assign the policy. */
538 snapshot_session_action->policy = copy;
539 status = LTTNG_ACTION_STATUS_OK;
540 copy = NULL;
541
542 end:
543 lttng_firing_policy_destroy(copy);
544 return status;
545 }
546
547 enum lttng_action_status lttng_action_snapshot_session_get_firing_policy(
548 const struct lttng_action *action,
549 const struct lttng_firing_policy **policy)
550 {
551 enum lttng_action_status status;
552 const struct lttng_action_snapshot_session *snapshot_session_action;
553
554 if (!action || !policy || !IS_SNAPSHOT_SESSION_ACTION(action)) {
555 status = LTTNG_ACTION_STATUS_INVALID;
556 goto end;
557 }
558
559 snapshot_session_action =
560 action_snapshot_session_from_action_const(action);
561
562 *policy = snapshot_session_action->policy;
563 status = LTTNG_ACTION_STATUS_OK;
564 end:
565 return status;
566 }
567
568 static const struct lttng_firing_policy *
569 lttng_action_snapshot_session_internal_get_firing_policy(
570 const struct lttng_action *action)
571 {
572 const struct lttng_action_snapshot_session *_action;
573 _action = action_snapshot_session_from_action_const(action);
574
575 return _action->policy;
576 }
This page took 0.040571 seconds and 3 git commands to generate.