trigger: implement trigger naming
[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>
3da864a9 15#include <common/optional.h>
a58c490f 16#include <assert.h>
242388e4 17#include <inttypes.h>
a58c490f
JG
18
19LTTNG_HIDDEN
20bool lttng_trigger_validate(struct lttng_trigger *trigger)
21{
22 bool valid;
23
24 if (!trigger) {
25 valid = false;
26 goto end;
27 }
28
64eafdf6
JR
29 if (!trigger->creds.uid.is_set) {
30 valid = false;
31 goto end;
32 }
33
a58c490f
JG
34 valid = lttng_condition_validate(trigger->condition) &&
35 lttng_action_validate(trigger->action);
36end:
37 return valid;
38}
39
40struct lttng_trigger *lttng_trigger_create(
41 struct lttng_condition *condition,
42 struct lttng_action *action)
43{
44 struct lttng_trigger *trigger = NULL;
45
46 if (!condition || !action) {
47 goto end;
48 }
49
50 trigger = zmalloc(sizeof(struct lttng_trigger));
51 if (!trigger) {
52 goto end;
53 }
54
f01d28b4
JR
55 urcu_ref_init(&trigger->ref);
56
7ca172c1 57 lttng_condition_get(condition);
a58c490f 58 trigger->condition = condition;
7ca172c1
JR
59
60 lttng_action_get(action);
a58c490f 61 trigger->action = action;
3da864a9 62
a58c490f
JG
63end:
64 return trigger;
65}
66
7ca172c1
JR
67/*
68 * Note: the lack of reference counting 'get' on the condition object is normal.
69 * This API was exposed as such in 2.11. The client is not expected to call
70 * lttng_condition_destroy on the returned object.
71 */
a58c490f
JG
72struct lttng_condition *lttng_trigger_get_condition(
73 struct lttng_trigger *trigger)
74{
75 return trigger ? trigger->condition : NULL;
76}
77
9b63a4aa
JG
78LTTNG_HIDDEN
79const struct lttng_condition *lttng_trigger_get_const_condition(
80 const struct lttng_trigger *trigger)
81{
82 return trigger->condition;
83}
84
7ca172c1
JR
85
86/*
87 * Note: the lack of reference counting 'get' on the action object is normal.
88 * This API was exposed as such in 2.11. The client is not expected to call
89 * lttng_action_destroy on the returned object.
90 */
e2ba1c78 91struct lttng_action *lttng_trigger_get_action(
a58c490f
JG
92 struct lttng_trigger *trigger)
93{
94 return trigger ? trigger->action : NULL;
95}
96
9b63a4aa
JG
97LTTNG_HIDDEN
98const struct lttng_action *lttng_trigger_get_const_action(
99 const struct lttng_trigger *trigger)
100{
101 return trigger->action;
102}
103
f01d28b4 104static void trigger_destroy_ref(struct urcu_ref *ref)
a58c490f 105{
f01d28b4
JR
106 struct lttng_trigger *trigger =
107 container_of(ref, struct lttng_trigger, ref);
7ca172c1
JR
108 struct lttng_action *action = lttng_trigger_get_action(trigger);
109 struct lttng_condition *condition =
110 lttng_trigger_get_condition(trigger);
111
7ca172c1
JR
112 assert(action);
113 assert(condition);
114
115 /* Release ownership. */
116 lttng_action_put(action);
117 lttng_condition_put(condition);
118
242388e4 119 free(trigger->name);
a58c490f
JG
120 free(trigger);
121}
122
f01d28b4
JR
123void lttng_trigger_destroy(struct lttng_trigger *trigger)
124{
125 lttng_trigger_put(trigger);
126}
127
a58c490f 128LTTNG_HIDDEN
c0a66c84
JG
129ssize_t lttng_trigger_create_from_payload(
130 struct lttng_payload_view *src_view,
a58c490f
JG
131 struct lttng_trigger **trigger)
132{
242388e4 133 ssize_t ret, offset = 0, condition_size, action_size, name_size = 0;
a58c490f
JG
134 struct lttng_condition *condition = NULL;
135 struct lttng_action *action = NULL;
136 const struct lttng_trigger_comm *trigger_comm;
242388e4 137 const char *name = NULL;
64eafdf6
JR
138 struct lttng_credentials creds = {
139 .uid = LTTNG_OPTIONAL_INIT_UNSET,
140 .gid = LTTNG_OPTIONAL_INIT_UNSET,
141 };
a58c490f
JG
142
143 if (!src_view || !trigger) {
144 ret = -1;
145 goto end;
146 }
147
148 /* lttng_trigger_comm header */
c0a66c84 149 trigger_comm = (typeof(trigger_comm)) src_view->buffer.data;
64eafdf6
JR
150
151 /* Set the trigger's creds. */
152 if (trigger_comm->uid > (uint64_t) ((uid_t) -1)) {
153 /* UID out of range for this platform. */
154 ret = -1;
155 goto end;
156 }
157
158 LTTNG_OPTIONAL_SET(&creds.uid, trigger_comm->uid);
159
a58c490f 160 offset += sizeof(*trigger_comm);
242388e4
JR
161
162 if (trigger_comm->name_length != 0) {
163 /* Name. */
164 const struct lttng_payload_view name_view =
165 lttng_payload_view_from_view(
166 src_view, offset, trigger_comm->name_length);
167
168 name = name_view.buffer.data;
169 if (!lttng_buffer_view_contains_string(&name_view.buffer, name,
170 trigger_comm->name_length)) {
171 ret = -1;
172 goto end;
173 }
174
175 offset += trigger_comm->name_length;
176 name_size = trigger_comm->name_length;
177 }
178
c0a66c84
JG
179 {
180 /* struct lttng_condition */
181 struct lttng_payload_view condition_view =
182 lttng_payload_view_from_view(
183 src_view, offset, -1);
184
185 condition_size = lttng_condition_create_from_payload(&condition_view,
186 &condition);
187 }
a58c490f 188
a58c490f
JG
189 if (condition_size < 0) {
190 ret = condition_size;
191 goto end;
192 }
c0a66c84 193
a58c490f 194 offset += condition_size;
c0a66c84
JG
195 {
196 /* struct lttng_action */
197 struct lttng_payload_view action_view =
198 lttng_payload_view_from_view(
199 src_view, offset, -1);
200
201 action_size = lttng_action_create_from_payload(&action_view, &action);
202 }
a58c490f 203
a58c490f
JG
204 if (action_size < 0) {
205 ret = action_size;
206 goto end;
207 }
208 offset += action_size;
209
210 /* Unexpected size of inner-elements; the buffer is corrupted. */
242388e4 211 if ((ssize_t) trigger_comm->length != condition_size + action_size + name_size) {
a58c490f
JG
212 ret = -1;
213 goto error;
214 }
215
216 *trigger = lttng_trigger_create(condition, action);
217 if (!*trigger) {
218 ret = -1;
219 goto error;
220 }
c0a66c84 221
64eafdf6
JR
222 lttng_trigger_set_credentials(*trigger, &creds);
223
7ca172c1
JR
224 /*
225 * The trigger object owns references to the action and condition
226 * objects.
227 */
228 lttng_condition_put(condition);
229 condition = NULL;
230
231 lttng_action_put(action);
232 action = NULL;
233
242388e4
JR
234 if (name) {
235 const enum lttng_trigger_status status =
236 lttng_trigger_set_name(*trigger, name);
237
238 if (status != LTTNG_TRIGGER_STATUS_OK) {
239 ret = -1;
240 goto end;
241 }
242 }
243
a58c490f 244 ret = offset;
7ca172c1 245
a58c490f
JG
246error:
247 lttng_condition_destroy(condition);
248 lttng_action_destroy(action);
7ca172c1 249end:
a58c490f
JG
250 return ret;
251}
252
253/*
a58c490f
JG
254 * Both elements are stored contiguously, see their "*_comm" structure
255 * for the detailed format.
256 */
257LTTNG_HIDDEN
3647288f 258int lttng_trigger_serialize(struct lttng_trigger *trigger,
c0a66c84 259 struct lttng_payload *payload)
a58c490f 260{
3647288f 261 int ret;
242388e4 262 size_t header_offset, size_before_payload, size_name;
c0a66c84 263 struct lttng_trigger_comm trigger_comm = {};
3647288f 264 struct lttng_trigger_comm *header;
64eafdf6
JR
265 const struct lttng_credentials *creds = NULL;
266
267 creds = lttng_trigger_get_credentials(trigger);
268 assert(creds);
269
270 trigger_comm.uid = LTTNG_OPTIONAL_GET(creds->uid);
a58c490f 271
242388e4
JR
272 if (trigger->name != NULL) {
273 size_name = strlen(trigger->name) + 1;
274 } else {
275 size_name = 0;
276 }
277
278 trigger_comm.name_length = size_name;
279
c0a66c84
JG
280 header_offset = payload->buffer.size;
281 ret = lttng_dynamic_buffer_append(&payload->buffer, &trigger_comm,
3647288f
JG
282 sizeof(trigger_comm));
283 if (ret) {
a58c490f
JG
284 goto end;
285 }
286
c0a66c84 287 size_before_payload = payload->buffer.size;
242388e4
JR
288
289 /* Trigger name. */
290 ret = lttng_dynamic_buffer_append(
291 &payload->buffer, trigger->name, size_name);
292 if (ret) {
293 goto end;
294 }
295
c0a66c84 296 ret = lttng_condition_serialize(trigger->condition, payload);
3647288f 297 if (ret) {
a58c490f
JG
298 goto end;
299 }
a58c490f 300
c0a66c84 301 ret = lttng_action_serialize(trigger->action, payload);
3647288f 302 if (ret) {
a58c490f
JG
303 goto end;
304 }
a58c490f 305
3647288f 306 /* Update payload size. */
c0a66c84
JG
307 header = (typeof(header)) (payload->buffer.data + header_offset);
308 header->length = payload->buffer.size - size_before_payload;
a58c490f
JG
309end:
310 return ret;
311}
3da864a9 312
85c06c44
JR
313LTTNG_HIDDEN
314bool lttng_trigger_is_equal(
315 const struct lttng_trigger *a, const struct lttng_trigger *b)
316{
317 /*
318 * Name is not taken into account since it is cosmetic only.
319 */
320 if (!lttng_condition_is_equal(a->condition, b->condition)) {
321 return false;
322 }
323
324 if (!lttng_action_is_equal(a->action, b->action)) {
325 return false;
326 }
327
328 if (!lttng_credentials_is_equal(lttng_trigger_get_credentials(a),
329 lttng_trigger_get_credentials(b))) {
330 return false;
331 }
332
333 return true;
334}
335
242388e4
JR
336enum lttng_trigger_status lttng_trigger_set_name(struct lttng_trigger *trigger,
337 const char* name)
338{
339 char *name_copy = NULL;
340 enum lttng_trigger_status status = LTTNG_TRIGGER_STATUS_OK;
341
342 if (!trigger || !name ||
343 strlen(name) == 0) {
344 status = LTTNG_TRIGGER_STATUS_INVALID;
345 goto end;
346 }
347
348 name_copy = strdup(name);
349 if (!name_copy) {
350 status = LTTNG_TRIGGER_STATUS_ERROR;
351 goto end;
352 }
353
354 free(trigger->name);
355
356 trigger->name = name_copy;
357 name_copy = NULL;
358end:
359 return status;
360}
361
362enum lttng_trigger_status lttng_trigger_get_name(
363 const struct lttng_trigger *trigger, const char **name)
364{
365 enum lttng_trigger_status status = LTTNG_TRIGGER_STATUS_OK;
366
367 if (!trigger || !name) {
368 status = LTTNG_TRIGGER_STATUS_INVALID;
369 goto end;
370 }
371
372 if (!trigger->name) {
373 status = LTTNG_TRIGGER_STATUS_UNSET;
374 }
375
376 *name = trigger->name;
377end:
378 return status;
379}
380
381LTTNG_HIDDEN
382int lttng_trigger_assign_name(struct lttng_trigger *dst,
383 const struct lttng_trigger *src)
384{
385 int ret = 0;
386 enum lttng_trigger_status status;
387
388 status = lttng_trigger_set_name(dst, src->name);
389 if (status != LTTNG_TRIGGER_STATUS_OK) {
390 ret = -1;
391 ERR("Failed to set name for trigger");
392 goto end;
393 }
394end:
395 return ret;
396}
397
398LTTNG_HIDDEN
399int lttng_trigger_generate_name(struct lttng_trigger *trigger,
400 uint64_t unique_id)
401{
402 int ret = 0;
403 char *generated_name = NULL;
404
405 ret = asprintf(&generated_name, "T%" PRIu64 "", unique_id);
406 if (ret < 0) {
407 ERR("Failed to generate trigger name");
408 ret = -1;
409 goto end;
410 }
411
412 ret = 0;
413 free(trigger->name);
414 trigger->name = generated_name;
415end:
416 return ret;
417}
418
f01d28b4
JR
419LTTNG_HIDDEN
420void lttng_trigger_get(struct lttng_trigger *trigger)
421{
422 urcu_ref_get(&trigger->ref);
423}
424
425LTTNG_HIDDEN
426void lttng_trigger_put(struct lttng_trigger *trigger)
427{
428 if (!trigger) {
429 return;
430 }
431
432 urcu_ref_put(&trigger->ref , trigger_destroy_ref);
433}
434
3da864a9
JR
435LTTNG_HIDDEN
436const struct lttng_credentials *lttng_trigger_get_credentials(
437 const struct lttng_trigger *trigger)
438{
64eafdf6 439 return &trigger->creds;
3da864a9
JR
440}
441
442LTTNG_HIDDEN
64eafdf6 443void lttng_trigger_set_credentials(struct lttng_trigger *trigger,
3da864a9
JR
444 const struct lttng_credentials *creds)
445{
446 assert(creds);
64eafdf6
JR
447 trigger->creds = *creds;
448}
449
450enum lttng_trigger_status lttng_trigger_set_owner_uid(
451 struct lttng_trigger *trigger, uid_t uid)
452{
453 enum lttng_trigger_status ret = LTTNG_TRIGGER_STATUS_OK;
454 const struct lttng_credentials creds = {
455 .uid = LTTNG_OPTIONAL_INIT_VALUE(uid),
456 .gid = LTTNG_OPTIONAL_INIT_UNSET,
457 };
458
459 if (!trigger) {
460 ret = LTTNG_TRIGGER_STATUS_INVALID;
461 goto end;
462 }
463
464 /* Client-side validation only to report a clearer error. */
465 if (geteuid() != 0) {
466 ret = LTTNG_TRIGGER_STATUS_PERMISSION_DENIED;
467 goto end;
468 }
469
470 lttng_trigger_set_credentials(trigger, &creds);
471
472end:
473 return ret;
474}
475
476enum lttng_trigger_status lttng_trigger_get_owner_uid(
477 const struct lttng_trigger *trigger, uid_t *uid)
478{
479 enum lttng_trigger_status ret = LTTNG_TRIGGER_STATUS_OK;
480 const struct lttng_credentials *creds = NULL;
481
482 if (!trigger || !uid ) {
483 ret = LTTNG_TRIGGER_STATUS_INVALID;
484 goto end;
485 }
486
487 if (!trigger->creds.uid.is_set ) {
488 ret = LTTNG_TRIGGER_STATUS_UNSET;
489 goto end;
490 }
491
492 creds = lttng_trigger_get_credentials(trigger);
493 *uid = lttng_credentials_get_uid(creds);
494
495end:
496 return ret;
3da864a9 497}
This page took 0.055997 seconds and 4 git commands to generate.