Clean-up: trigger: use condition and action put
[lttng-tools.git] / src / common / trigger.c
... / ...
CommitLineData
1/*
2 * Copyright (C) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8#include <lttng/trigger/trigger-internal.h>
9#include <lttng/condition/condition-internal.h>
10#include <lttng/action/action-internal.h>
11#include <common/credentials.h>
12#include <common/payload.h>
13#include <common/payload-view.h>
14#include <common/error.h>
15#include <common/dynamic-array.h>
16#include <common/optional.h>
17#include <assert.h>
18#include <inttypes.h>
19
20LTTNG_HIDDEN
21bool lttng_trigger_validate(struct lttng_trigger *trigger)
22{
23 bool valid;
24
25 if (!trigger) {
26 valid = false;
27 goto end;
28 }
29
30 if (!trigger->creds.uid.is_set) {
31 valid = false;
32 goto end;
33 }
34
35 valid = lttng_condition_validate(trigger->condition) &&
36 lttng_action_validate(trigger->action);
37end:
38 return valid;
39}
40
41struct lttng_trigger *lttng_trigger_create(
42 struct lttng_condition *condition,
43 struct lttng_action *action)
44{
45 struct lttng_trigger *trigger = NULL;
46
47 if (!condition || !action) {
48 goto end;
49 }
50
51 trigger = zmalloc(sizeof(struct lttng_trigger));
52 if (!trigger) {
53 goto end;
54 }
55
56 urcu_ref_init(&trigger->ref);
57
58 lttng_condition_get(condition);
59 trigger->condition = condition;
60
61 lttng_action_get(action);
62 trigger->action = action;
63
64end:
65 return trigger;
66}
67
68/*
69 * Note: the lack of reference counting 'get' on the condition object is normal.
70 * This API was exposed as such in 2.11. The client is not expected to call
71 * lttng_condition_destroy on the returned object.
72 */
73struct lttng_condition *lttng_trigger_get_condition(
74 struct lttng_trigger *trigger)
75{
76 return trigger ? trigger->condition : NULL;
77}
78
79LTTNG_HIDDEN
80const struct lttng_condition *lttng_trigger_get_const_condition(
81 const struct lttng_trigger *trigger)
82{
83 return trigger->condition;
84}
85
86
87/*
88 * Note: the lack of reference counting 'get' on the action object is normal.
89 * This API was exposed as such in 2.11. The client is not expected to call
90 * lttng_action_destroy on the returned object.
91 */
92struct lttng_action *lttng_trigger_get_action(
93 struct lttng_trigger *trigger)
94{
95 return trigger ? trigger->action : NULL;
96}
97
98LTTNG_HIDDEN
99const struct lttng_action *lttng_trigger_get_const_action(
100 const struct lttng_trigger *trigger)
101{
102 return trigger->action;
103}
104
105static void trigger_destroy_ref(struct urcu_ref *ref)
106{
107 struct lttng_trigger *trigger =
108 container_of(ref, struct lttng_trigger, ref);
109 struct lttng_action *action = lttng_trigger_get_action(trigger);
110 struct lttng_condition *condition =
111 lttng_trigger_get_condition(trigger);
112
113 assert(action);
114 assert(condition);
115
116 /* Release ownership. */
117 lttng_action_put(action);
118 lttng_condition_put(condition);
119
120 free(trigger->name);
121 free(trigger);
122}
123
124void lttng_trigger_destroy(struct lttng_trigger *trigger)
125{
126 lttng_trigger_put(trigger);
127}
128
129LTTNG_HIDDEN
130ssize_t lttng_trigger_create_from_payload(
131 struct lttng_payload_view *src_view,
132 struct lttng_trigger **trigger)
133{
134 ssize_t ret, offset = 0, condition_size, action_size, name_size = 0;
135 struct lttng_condition *condition = NULL;
136 struct lttng_action *action = NULL;
137 const struct lttng_trigger_comm *trigger_comm;
138 const char *name = NULL;
139 struct lttng_credentials creds = {
140 .uid = LTTNG_OPTIONAL_INIT_UNSET,
141 .gid = LTTNG_OPTIONAL_INIT_UNSET,
142 };
143 const struct lttng_payload_view trigger_comm_view =
144 lttng_payload_view_from_view(
145 src_view, 0, sizeof(*trigger_comm));
146
147 if (!src_view || !trigger) {
148 ret = -1;
149 goto end;
150 }
151
152 if (!lttng_payload_view_is_valid(&trigger_comm_view)) {
153 /* Payload not large enough to contain the header. */
154 ret = -1;
155 goto end;
156 }
157
158 /* lttng_trigger_comm header */
159 trigger_comm = (typeof(trigger_comm)) trigger_comm_view.buffer.data;
160
161 /* Set the trigger's creds. */
162 if (trigger_comm->uid > (uint64_t) ((uid_t) -1)) {
163 /* UID out of range for this platform. */
164 ret = -1;
165 goto end;
166 }
167
168 LTTNG_OPTIONAL_SET(&creds.uid, trigger_comm->uid);
169
170 offset += sizeof(*trigger_comm);
171
172 if (trigger_comm->name_length != 0) {
173 /* Name. */
174 const struct lttng_payload_view name_view =
175 lttng_payload_view_from_view(
176 src_view, offset,
177 trigger_comm->name_length);
178
179 if (!lttng_payload_view_is_valid(&name_view)) {
180 ret = -1;
181 goto end;
182 }
183
184 name = name_view.buffer.data;
185 if (!lttng_buffer_view_contains_string(&name_view.buffer, name,
186 trigger_comm->name_length)) {
187 ret = -1;
188 goto end;
189 }
190
191 offset += trigger_comm->name_length;
192 name_size = trigger_comm->name_length;
193 }
194
195 {
196 /* struct lttng_condition */
197 struct lttng_payload_view condition_view =
198 lttng_payload_view_from_view(
199 src_view, offset, -1);
200
201 condition_size = lttng_condition_create_from_payload(&condition_view,
202 &condition);
203 }
204
205 if (condition_size < 0) {
206 ret = condition_size;
207 goto end;
208 }
209
210 offset += condition_size;
211 {
212 /* struct lttng_action */
213 struct lttng_payload_view action_view =
214 lttng_payload_view_from_view(
215 src_view, offset, -1);
216
217 action_size = lttng_action_create_from_payload(&action_view, &action);
218 }
219
220 if (action_size < 0) {
221 ret = action_size;
222 goto end;
223 }
224 offset += action_size;
225
226 /* Unexpected size of inner-elements; the buffer is corrupted. */
227 if ((ssize_t) trigger_comm->length != condition_size + action_size + name_size) {
228 ret = -1;
229 goto error;
230 }
231
232 *trigger = lttng_trigger_create(condition, action);
233 if (!*trigger) {
234 ret = -1;
235 goto error;
236 }
237
238 lttng_trigger_set_credentials(*trigger, &creds);
239
240 /*
241 * The trigger object owns references to the action and condition
242 * objects.
243 */
244 lttng_condition_put(condition);
245 condition = NULL;
246
247 lttng_action_put(action);
248 action = NULL;
249
250 if (name) {
251 const enum lttng_trigger_status status =
252 lttng_trigger_set_name(*trigger, name);
253
254 if (status != LTTNG_TRIGGER_STATUS_OK) {
255 ret = -1;
256 goto end;
257 }
258 }
259
260 ret = offset;
261
262error:
263 lttng_condition_put(condition);
264 lttng_action_put(action);
265end:
266 return ret;
267}
268
269/*
270 * Both elements are stored contiguously, see their "*_comm" structure
271 * for the detailed format.
272 */
273LTTNG_HIDDEN
274int lttng_trigger_serialize(const struct lttng_trigger *trigger,
275 struct lttng_payload *payload)
276{
277 int ret;
278 size_t header_offset, size_before_payload, size_name;
279 struct lttng_trigger_comm trigger_comm = {};
280 struct lttng_trigger_comm *header;
281 const struct lttng_credentials *creds = NULL;
282
283 creds = lttng_trigger_get_credentials(trigger);
284 assert(creds);
285
286 trigger_comm.uid = LTTNG_OPTIONAL_GET(creds->uid);
287
288 if (trigger->name != NULL) {
289 size_name = strlen(trigger->name) + 1;
290 } else {
291 size_name = 0;
292 }
293
294 trigger_comm.name_length = size_name;
295
296 header_offset = payload->buffer.size;
297 ret = lttng_dynamic_buffer_append(&payload->buffer, &trigger_comm,
298 sizeof(trigger_comm));
299 if (ret) {
300 goto end;
301 }
302
303 size_before_payload = payload->buffer.size;
304
305 /* Trigger name. */
306 ret = lttng_dynamic_buffer_append(
307 &payload->buffer, trigger->name, size_name);
308 if (ret) {
309 goto end;
310 }
311
312 ret = lttng_condition_serialize(trigger->condition, payload);
313 if (ret) {
314 goto end;
315 }
316
317 ret = lttng_action_serialize(trigger->action, payload);
318 if (ret) {
319 goto end;
320 }
321
322 /* Update payload size. */
323 header = (typeof(header)) (payload->buffer.data + header_offset);
324 header->length = payload->buffer.size - size_before_payload;
325end:
326 return ret;
327}
328
329LTTNG_HIDDEN
330bool lttng_trigger_is_equal(
331 const struct lttng_trigger *a, const struct lttng_trigger *b)
332{
333 /*
334 * Name is not taken into account since it is cosmetic only.
335 */
336 if (!lttng_condition_is_equal(a->condition, b->condition)) {
337 return false;
338 }
339
340 if (!lttng_action_is_equal(a->action, b->action)) {
341 return false;
342 }
343
344 if (!lttng_credentials_is_equal(lttng_trigger_get_credentials(a),
345 lttng_trigger_get_credentials(b))) {
346 return false;
347 }
348
349 return true;
350}
351
352enum lttng_trigger_status lttng_trigger_set_name(struct lttng_trigger *trigger,
353 const char* name)
354{
355 char *name_copy = NULL;
356 enum lttng_trigger_status status = LTTNG_TRIGGER_STATUS_OK;
357
358 if (!trigger || !name ||
359 strlen(name) == 0) {
360 status = LTTNG_TRIGGER_STATUS_INVALID;
361 goto end;
362 }
363
364 name_copy = strdup(name);
365 if (!name_copy) {
366 status = LTTNG_TRIGGER_STATUS_ERROR;
367 goto end;
368 }
369
370 free(trigger->name);
371
372 trigger->name = name_copy;
373 name_copy = NULL;
374end:
375 return status;
376}
377
378enum lttng_trigger_status lttng_trigger_get_name(
379 const struct lttng_trigger *trigger, const char **name)
380{
381 enum lttng_trigger_status status = LTTNG_TRIGGER_STATUS_OK;
382
383 if (!trigger || !name) {
384 status = LTTNG_TRIGGER_STATUS_INVALID;
385 goto end;
386 }
387
388 if (!trigger->name) {
389 status = LTTNG_TRIGGER_STATUS_UNSET;
390 }
391
392 *name = trigger->name;
393end:
394 return status;
395}
396
397LTTNG_HIDDEN
398int lttng_trigger_assign_name(struct lttng_trigger *dst,
399 const struct lttng_trigger *src)
400{
401 int ret = 0;
402 enum lttng_trigger_status status;
403
404 status = lttng_trigger_set_name(dst, src->name);
405 if (status != LTTNG_TRIGGER_STATUS_OK) {
406 ret = -1;
407 ERR("Failed to set name for trigger");
408 goto end;
409 }
410end:
411 return ret;
412}
413
414LTTNG_HIDDEN
415void lttng_trigger_set_tracer_token(struct lttng_trigger *trigger,
416 uint64_t token)
417{
418 assert(trigger);
419 LTTNG_OPTIONAL_SET(&trigger->tracer_token, token);
420}
421
422LTTNG_HIDDEN
423uint64_t lttng_trigger_get_tracer_token(const struct lttng_trigger *trigger)
424{
425 assert(trigger);
426
427 return LTTNG_OPTIONAL_GET(trigger->tracer_token);
428}
429
430LTTNG_HIDDEN
431int lttng_trigger_generate_name(struct lttng_trigger *trigger,
432 uint64_t unique_id)
433{
434 int ret = 0;
435 char *generated_name = NULL;
436
437 ret = asprintf(&generated_name, "T%" PRIu64 "", unique_id);
438 if (ret < 0) {
439 ERR("Failed to generate trigger name");
440 ret = -1;
441 goto end;
442 }
443
444 ret = 0;
445 free(trigger->name);
446 trigger->name = generated_name;
447end:
448 return ret;
449}
450
451LTTNG_HIDDEN
452void lttng_trigger_get(struct lttng_trigger *trigger)
453{
454 urcu_ref_get(&trigger->ref);
455}
456
457LTTNG_HIDDEN
458void lttng_trigger_put(struct lttng_trigger *trigger)
459{
460 if (!trigger) {
461 return;
462 }
463
464 urcu_ref_put(&trigger->ref , trigger_destroy_ref);
465}
466
467static void delete_trigger_array_element(void *ptr)
468{
469 struct lttng_trigger *trigger = ptr;
470
471 lttng_trigger_put(trigger);
472}
473
474LTTNG_HIDDEN
475struct lttng_triggers *lttng_triggers_create(void)
476{
477 struct lttng_triggers *triggers = NULL;
478
479 triggers = zmalloc(sizeof(*triggers));
480 if (!triggers) {
481 goto end;
482 }
483
484 lttng_dynamic_pointer_array_init(&triggers->array, delete_trigger_array_element);
485
486end:
487 return triggers;
488}
489
490LTTNG_HIDDEN
491struct lttng_trigger *lttng_triggers_borrow_mutable_at_index(
492 const struct lttng_triggers *triggers, unsigned int index)
493{
494 struct lttng_trigger *trigger = NULL;
495
496 assert(triggers);
497 if (index >= lttng_dynamic_pointer_array_get_count(&triggers->array)) {
498 goto end;
499 }
500
501 trigger = (struct lttng_trigger *)
502 lttng_dynamic_pointer_array_get_pointer(
503 &triggers->array, index);
504end:
505 return trigger;
506}
507
508LTTNG_HIDDEN
509int lttng_triggers_add(
510 struct lttng_triggers *triggers, struct lttng_trigger *trigger)
511{
512 int ret;
513
514 assert(triggers);
515 assert(trigger);
516
517 lttng_trigger_get(trigger);
518
519 ret = lttng_dynamic_pointer_array_add_pointer(&triggers->array, trigger);
520 if (ret) {
521 lttng_trigger_put(trigger);
522 }
523
524 return ret;
525}
526
527const struct lttng_trigger *lttng_triggers_get_at_index(
528 const struct lttng_triggers *triggers, unsigned int index)
529{
530 return lttng_triggers_borrow_mutable_at_index(triggers, index);
531}
532
533enum lttng_trigger_status lttng_triggers_get_count(const struct lttng_triggers *triggers, unsigned int *count)
534{
535 enum lttng_trigger_status status = LTTNG_TRIGGER_STATUS_OK;
536
537 if (!triggers || !count) {
538 status = LTTNG_TRIGGER_STATUS_INVALID;
539 goto end;
540 }
541
542 *count = lttng_dynamic_pointer_array_get_count(&triggers->array);
543end:
544 return status;
545}
546
547void lttng_triggers_destroy(struct lttng_triggers *triggers)
548{
549 if (!triggers) {
550 return;
551 }
552
553 lttng_dynamic_pointer_array_reset(&triggers->array);
554 free(triggers);
555}
556
557int lttng_triggers_serialize(const struct lttng_triggers *triggers,
558 struct lttng_payload *payload)
559{
560 int ret;
561 unsigned int i, count;
562 size_t size_before_payload;
563 struct lttng_triggers_comm triggers_comm = {};
564 struct lttng_triggers_comm *header;
565 enum lttng_trigger_status status;
566 const size_t header_offset = payload->buffer.size;
567
568 status = lttng_triggers_get_count(triggers, &count);
569 if (status != LTTNG_TRIGGER_STATUS_OK) {
570 ret = LTTNG_ERR_INVALID;
571 goto end;
572 }
573
574 triggers_comm.count = count;
575
576 /* Placeholder header; updated at the end. */
577 ret = lttng_dynamic_buffer_append(&payload->buffer, &triggers_comm,
578 sizeof(triggers_comm));
579 if (ret) {
580 goto end;
581 }
582
583 size_before_payload = payload->buffer.size;
584
585 for (i = 0; i < count; i++) {
586 const struct lttng_trigger *trigger =
587 lttng_triggers_get_at_index(triggers, i);
588
589 assert(trigger);
590
591 ret = lttng_trigger_serialize(trigger, payload);
592 if (ret) {
593 goto end;
594 }
595 }
596
597 /* Update payload size. */
598 header = (struct lttng_triggers_comm *) ((char *) payload->buffer.data + header_offset);
599 header->length = payload->buffer.size - size_before_payload;
600end:
601 return ret;
602}
603
604LTTNG_HIDDEN
605ssize_t lttng_triggers_create_from_payload(
606 struct lttng_payload_view *src_view,
607 struct lttng_triggers **triggers)
608{
609 ssize_t ret, offset = 0, triggers_size = 0;
610 unsigned int i;
611 const struct lttng_triggers_comm *triggers_comm;
612 struct lttng_triggers *local_triggers = NULL;
613
614 if (!src_view || !triggers) {
615 ret = -1;
616 goto error;
617 }
618
619 /* lttng_trigger_comms header */
620 triggers_comm = (const struct lttng_triggers_comm *) src_view->buffer.data;
621 offset += sizeof(*triggers_comm);
622
623 local_triggers = lttng_triggers_create();
624 if (!local_triggers) {
625 ret = -1;
626 goto error;
627 }
628
629 for (i = 0; i < triggers_comm->count; i++) {
630 struct lttng_trigger *trigger = NULL;
631 struct lttng_payload_view trigger_view =
632 lttng_payload_view_from_view(src_view, offset, -1);
633 ssize_t trigger_size;
634
635 trigger_size = lttng_trigger_create_from_payload(
636 &trigger_view, &trigger);
637 if (trigger_size < 0) {
638 ret = trigger_size;
639 goto error;
640 }
641
642 /* Transfer ownership of the trigger to the collection. */
643 ret = lttng_triggers_add(local_triggers, trigger);
644 lttng_trigger_put(trigger);
645 if (ret < 0) {
646 ret = -1;
647 goto error;
648 }
649
650 offset += trigger_size;
651 triggers_size += trigger_size;
652 }
653
654 /* Unexpected size of inner-elements; the buffer is corrupted. */
655 if ((ssize_t) triggers_comm->length != triggers_size) {
656 ret = -1;
657 goto error;
658 }
659
660 /* Pass ownership to caller. */
661 *triggers = local_triggers;
662 local_triggers = NULL;
663
664 ret = offset;
665error:
666
667 lttng_triggers_destroy(local_triggers);
668 return ret;
669}
670
671LTTNG_HIDDEN
672const struct lttng_credentials *lttng_trigger_get_credentials(
673 const struct lttng_trigger *trigger)
674{
675 return &trigger->creds;
676}
677
678LTTNG_HIDDEN
679void lttng_trigger_set_credentials(struct lttng_trigger *trigger,
680 const struct lttng_credentials *creds)
681{
682 assert(creds);
683 trigger->creds = *creds;
684}
685
686enum lttng_trigger_status lttng_trigger_set_owner_uid(
687 struct lttng_trigger *trigger, uid_t uid)
688{
689 enum lttng_trigger_status ret = LTTNG_TRIGGER_STATUS_OK;
690 const struct lttng_credentials creds = {
691 .uid = LTTNG_OPTIONAL_INIT_VALUE(uid),
692 .gid = LTTNG_OPTIONAL_INIT_UNSET,
693 };
694
695 if (!trigger) {
696 ret = LTTNG_TRIGGER_STATUS_INVALID;
697 goto end;
698 }
699
700 /* Client-side validation only to report a clearer error. */
701 if (geteuid() != 0) {
702 ret = LTTNG_TRIGGER_STATUS_PERMISSION_DENIED;
703 goto end;
704 }
705
706 lttng_trigger_set_credentials(trigger, &creds);
707
708end:
709 return ret;
710}
711
712enum lttng_trigger_status lttng_trigger_get_owner_uid(
713 const struct lttng_trigger *trigger, uid_t *uid)
714{
715 enum lttng_trigger_status ret = LTTNG_TRIGGER_STATUS_OK;
716 const struct lttng_credentials *creds = NULL;
717
718 if (!trigger || !uid ) {
719 ret = LTTNG_TRIGGER_STATUS_INVALID;
720 goto end;
721 }
722
723 if (!trigger->creds.uid.is_set ) {
724 ret = LTTNG_TRIGGER_STATUS_UNSET;
725 goto end;
726 }
727
728 creds = lttng_trigger_get_credentials(trigger);
729 *uid = lttng_credentials_get_uid(creds);
730
731end:
732 return ret;
733}
This page took 0.025802 seconds and 4 git commands to generate.