relayd: logging of `trace chunk exists` command refers to the wrong command
[lttng-tools.git] / src / common / trigger.c
CommitLineData
a58c490f 1/*
ab5be9fa 2 * Copyright (C) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
a58c490f 3 *
ab5be9fa 4 * SPDX-License-Identifier: LGPL-2.1-only
a58c490f 5 *
a58c490f
JG
6 */
7
8#include <lttng/trigger/trigger-internal.h>
9#include <lttng/condition/condition-internal.h>
10#include <lttng/action/action-internal.h>
3da864a9 11#include <common/credentials.h>
9e620ea7
JG
12#include <common/payload.h>
13#include <common/payload-view.h>
a58c490f 14#include <common/error.h>
a02903c0 15#include <common/dynamic-array.h>
3da864a9 16#include <common/optional.h>
a58c490f 17#include <assert.h>
242388e4 18#include <inttypes.h>
a58c490f
JG
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
64eafdf6
JR
30 if (!trigger->creds.uid.is_set) {
31 valid = false;
32 goto end;
33 }
34
a58c490f
JG
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
f01d28b4
JR
56 urcu_ref_init(&trigger->ref);
57
7ca172c1 58 lttng_condition_get(condition);
a58c490f 59 trigger->condition = condition;
7ca172c1
JR
60
61 lttng_action_get(action);
a58c490f 62 trigger->action = action;
3da864a9 63
a58c490f
JG
64end:
65 return trigger;
66}
67
7ca172c1
JR
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 */
a58c490f
JG
73struct lttng_condition *lttng_trigger_get_condition(
74 struct lttng_trigger *trigger)
75{
76 return trigger ? trigger->condition : NULL;
77}
78
9b63a4aa
JG
79LTTNG_HIDDEN
80const struct lttng_condition *lttng_trigger_get_const_condition(
81 const struct lttng_trigger *trigger)
82{
83 return trigger->condition;
84}
85
7ca172c1
JR
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 */
e2ba1c78 92struct lttng_action *lttng_trigger_get_action(
a58c490f
JG
93 struct lttng_trigger *trigger)
94{
95 return trigger ? trigger->action : NULL;
96}
97
9b63a4aa
JG
98LTTNG_HIDDEN
99const struct lttng_action *lttng_trigger_get_const_action(
100 const struct lttng_trigger *trigger)
101{
102 return trigger->action;
103}
104
f01d28b4 105static void trigger_destroy_ref(struct urcu_ref *ref)
a58c490f 106{
f01d28b4
JR
107 struct lttng_trigger *trigger =
108 container_of(ref, struct lttng_trigger, ref);
7ca172c1
JR
109 struct lttng_action *action = lttng_trigger_get_action(trigger);
110 struct lttng_condition *condition =
111 lttng_trigger_get_condition(trigger);
112
7ca172c1
JR
113 assert(action);
114 assert(condition);
115
116 /* Release ownership. */
117 lttng_action_put(action);
118 lttng_condition_put(condition);
119
242388e4 120 free(trigger->name);
a58c490f
JG
121 free(trigger);
122}
123
f01d28b4
JR
124void lttng_trigger_destroy(struct lttng_trigger *trigger)
125{
126 lttng_trigger_put(trigger);
127}
128
a58c490f 129LTTNG_HIDDEN
c0a66c84
JG
130ssize_t lttng_trigger_create_from_payload(
131 struct lttng_payload_view *src_view,
a58c490f
JG
132 struct lttng_trigger **trigger)
133{
242388e4 134 ssize_t ret, offset = 0, condition_size, action_size, name_size = 0;
a58c490f
JG
135 struct lttng_condition *condition = NULL;
136 struct lttng_action *action = NULL;
137 const struct lttng_trigger_comm *trigger_comm;
242388e4 138 const char *name = NULL;
64eafdf6
JR
139 struct lttng_credentials creds = {
140 .uid = LTTNG_OPTIONAL_INIT_UNSET,
141 .gid = LTTNG_OPTIONAL_INIT_UNSET,
142 };
a58c490f
JG
143
144 if (!src_view || !trigger) {
145 ret = -1;
146 goto end;
147 }
148
149 /* lttng_trigger_comm header */
c0a66c84 150 trigger_comm = (typeof(trigger_comm)) src_view->buffer.data;
64eafdf6
JR
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
a58c490f 161 offset += sizeof(*trigger_comm);
242388e4
JR
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
c0a66c84
JG
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 }
a58c490f 189
a58c490f
JG
190 if (condition_size < 0) {
191 ret = condition_size;
192 goto end;
193 }
c0a66c84 194
a58c490f 195 offset += condition_size;
c0a66c84
JG
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 }
a58c490f 204
a58c490f
JG
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. */
242388e4 212 if ((ssize_t) trigger_comm->length != condition_size + action_size + name_size) {
a58c490f
JG
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 }
c0a66c84 222
64eafdf6
JR
223 lttng_trigger_set_credentials(*trigger, &creds);
224
7ca172c1
JR
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
242388e4
JR
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
a58c490f 245 ret = offset;
7ca172c1 246
a58c490f
JG
247error:
248 lttng_condition_destroy(condition);
249 lttng_action_destroy(action);
7ca172c1 250end:
a58c490f
JG
251 return ret;
252}
253
254/*
a58c490f
JG
255 * Both elements are stored contiguously, see their "*_comm" structure
256 * for the detailed format.
257 */
258LTTNG_HIDDEN
a02903c0 259int lttng_trigger_serialize(const struct lttng_trigger *trigger,
c0a66c84 260 struct lttng_payload *payload)
a58c490f 261{
3647288f 262 int ret;
242388e4 263 size_t header_offset, size_before_payload, size_name;
c0a66c84 264 struct lttng_trigger_comm trigger_comm = {};
3647288f 265 struct lttng_trigger_comm *header;
64eafdf6
JR
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);
a58c490f 272
242388e4
JR
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
c0a66c84
JG
281 header_offset = payload->buffer.size;
282 ret = lttng_dynamic_buffer_append(&payload->buffer, &trigger_comm,
3647288f
JG
283 sizeof(trigger_comm));
284 if (ret) {
a58c490f
JG
285 goto end;
286 }
287
c0a66c84 288 size_before_payload = payload->buffer.size;
242388e4
JR
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
c0a66c84 297 ret = lttng_condition_serialize(trigger->condition, payload);
3647288f 298 if (ret) {
a58c490f
JG
299 goto end;
300 }
a58c490f 301
c0a66c84 302 ret = lttng_action_serialize(trigger->action, payload);
3647288f 303 if (ret) {
a58c490f
JG
304 goto end;
305 }
a58c490f 306
3647288f 307 /* Update payload size. */
c0a66c84
JG
308 header = (typeof(header)) (payload->buffer.data + header_offset);
309 header->length = payload->buffer.size - size_before_payload;
a58c490f
JG
310end:
311 return ret;
312}
3da864a9 313
85c06c44
JR
314LTTNG_HIDDEN
315bool 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
242388e4
JR
337enum 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;
359end:
360 return status;
361}
362
363enum 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;
378end:
379 return status;
380}
381
382LTTNG_HIDDEN
383int 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 }
395end:
396 return ret;
397}
398
e6887944
JR
399LTTNG_HIDDEN
400void 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
407LTTNG_HIDDEN
408uint64_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
242388e4
JR
415LTTNG_HIDDEN
416int 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;
432end:
433 return ret;
434}
435
f01d28b4
JR
436LTTNG_HIDDEN
437void lttng_trigger_get(struct lttng_trigger *trigger)
438{
439 urcu_ref_get(&trigger->ref);
440}
441
442LTTNG_HIDDEN
443void 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
a02903c0
JR
452static void delete_trigger_array_element(void *ptr)
453{
454 struct lttng_trigger *trigger = ptr;
455
456 lttng_trigger_put(trigger);
457}
458
459LTTNG_HIDDEN
460struct 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
471end:
472 return triggers;
473}
474
475LTTNG_HIDDEN
476struct 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);
489end:
490 return trigger;
491}
492
493LTTNG_HIDDEN
494int 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
512const 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
518enum 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);
528end:
529 return status;
530}
531
532void 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
542int 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;
585end:
586 return ret;
587}
588
589LTTNG_HIDDEN
590ssize_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;
650error:
651
652 lttng_triggers_destroy(local_triggers);
653 return ret;
654}
655
3da864a9
JR
656LTTNG_HIDDEN
657const struct lttng_credentials *lttng_trigger_get_credentials(
658 const struct lttng_trigger *trigger)
659{
64eafdf6 660 return &trigger->creds;
3da864a9
JR
661}
662
663LTTNG_HIDDEN
64eafdf6 664void lttng_trigger_set_credentials(struct lttng_trigger *trigger,
3da864a9
JR
665 const struct lttng_credentials *creds)
666{
667 assert(creds);
64eafdf6
JR
668 trigger->creds = *creds;
669}
670
671enum 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
693end:
694 return ret;
695}
696
697enum 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
716end:
717 return ret;
3da864a9 718}
This page took 0.110689 seconds and 4 git commands to generate.