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