trigger: implement trigger naming
[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/optional.h>
16 #include <assert.h>
17 #include <inttypes.h>
18
19 LTTNG_HIDDEN
20 bool lttng_trigger_validate(struct lttng_trigger *trigger)
21 {
22 bool valid;
23
24 if (!trigger) {
25 valid = false;
26 goto end;
27 }
28
29 if (!trigger->creds.uid.is_set) {
30 valid = false;
31 goto end;
32 }
33
34 valid = lttng_condition_validate(trigger->condition) &&
35 lttng_action_validate(trigger->action);
36 end:
37 return valid;
38 }
39
40 struct 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
55 urcu_ref_init(&trigger->ref);
56
57 lttng_condition_get(condition);
58 trigger->condition = condition;
59
60 lttng_action_get(action);
61 trigger->action = action;
62
63 end:
64 return trigger;
65 }
66
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 */
72 struct lttng_condition *lttng_trigger_get_condition(
73 struct lttng_trigger *trigger)
74 {
75 return trigger ? trigger->condition : NULL;
76 }
77
78 LTTNG_HIDDEN
79 const struct lttng_condition *lttng_trigger_get_const_condition(
80 const struct lttng_trigger *trigger)
81 {
82 return trigger->condition;
83 }
84
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 */
91 struct lttng_action *lttng_trigger_get_action(
92 struct lttng_trigger *trigger)
93 {
94 return trigger ? trigger->action : NULL;
95 }
96
97 LTTNG_HIDDEN
98 const struct lttng_action *lttng_trigger_get_const_action(
99 const struct lttng_trigger *trigger)
100 {
101 return trigger->action;
102 }
103
104 static void trigger_destroy_ref(struct urcu_ref *ref)
105 {
106 struct lttng_trigger *trigger =
107 container_of(ref, struct lttng_trigger, ref);
108 struct lttng_action *action = lttng_trigger_get_action(trigger);
109 struct lttng_condition *condition =
110 lttng_trigger_get_condition(trigger);
111
112 assert(action);
113 assert(condition);
114
115 /* Release ownership. */
116 lttng_action_put(action);
117 lttng_condition_put(condition);
118
119 free(trigger->name);
120 free(trigger);
121 }
122
123 void lttng_trigger_destroy(struct lttng_trigger *trigger)
124 {
125 lttng_trigger_put(trigger);
126 }
127
128 LTTNG_HIDDEN
129 ssize_t lttng_trigger_create_from_payload(
130 struct lttng_payload_view *src_view,
131 struct lttng_trigger **trigger)
132 {
133 ssize_t ret, offset = 0, condition_size, action_size, name_size = 0;
134 struct lttng_condition *condition = NULL;
135 struct lttng_action *action = NULL;
136 const struct lttng_trigger_comm *trigger_comm;
137 const char *name = NULL;
138 struct lttng_credentials creds = {
139 .uid = LTTNG_OPTIONAL_INIT_UNSET,
140 .gid = LTTNG_OPTIONAL_INIT_UNSET,
141 };
142
143 if (!src_view || !trigger) {
144 ret = -1;
145 goto end;
146 }
147
148 /* lttng_trigger_comm header */
149 trigger_comm = (typeof(trigger_comm)) src_view->buffer.data;
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
160 offset += sizeof(*trigger_comm);
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
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 }
188
189 if (condition_size < 0) {
190 ret = condition_size;
191 goto end;
192 }
193
194 offset += condition_size;
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 }
203
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. */
211 if ((ssize_t) trigger_comm->length != condition_size + action_size + name_size) {
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 }
221
222 lttng_trigger_set_credentials(*trigger, &creds);
223
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
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
244 ret = offset;
245
246 error:
247 lttng_condition_destroy(condition);
248 lttng_action_destroy(action);
249 end:
250 return ret;
251 }
252
253 /*
254 * Both elements are stored contiguously, see their "*_comm" structure
255 * for the detailed format.
256 */
257 LTTNG_HIDDEN
258 int lttng_trigger_serialize(struct lttng_trigger *trigger,
259 struct lttng_payload *payload)
260 {
261 int ret;
262 size_t header_offset, size_before_payload, size_name;
263 struct lttng_trigger_comm trigger_comm = {};
264 struct lttng_trigger_comm *header;
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);
271
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
280 header_offset = payload->buffer.size;
281 ret = lttng_dynamic_buffer_append(&payload->buffer, &trigger_comm,
282 sizeof(trigger_comm));
283 if (ret) {
284 goto end;
285 }
286
287 size_before_payload = payload->buffer.size;
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
296 ret = lttng_condition_serialize(trigger->condition, payload);
297 if (ret) {
298 goto end;
299 }
300
301 ret = lttng_action_serialize(trigger->action, payload);
302 if (ret) {
303 goto end;
304 }
305
306 /* Update payload size. */
307 header = (typeof(header)) (payload->buffer.data + header_offset);
308 header->length = payload->buffer.size - size_before_payload;
309 end:
310 return ret;
311 }
312
313 LTTNG_HIDDEN
314 bool 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
336 enum 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;
358 end:
359 return status;
360 }
361
362 enum 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;
377 end:
378 return status;
379 }
380
381 LTTNG_HIDDEN
382 int 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 }
394 end:
395 return ret;
396 }
397
398 LTTNG_HIDDEN
399 int 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;
415 end:
416 return ret;
417 }
418
419 LTTNG_HIDDEN
420 void lttng_trigger_get(struct lttng_trigger *trigger)
421 {
422 urcu_ref_get(&trigger->ref);
423 }
424
425 LTTNG_HIDDEN
426 void 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
435 LTTNG_HIDDEN
436 const struct lttng_credentials *lttng_trigger_get_credentials(
437 const struct lttng_trigger *trigger)
438 {
439 return &trigger->creds;
440 }
441
442 LTTNG_HIDDEN
443 void lttng_trigger_set_credentials(struct lttng_trigger *trigger,
444 const struct lttng_credentials *creds)
445 {
446 assert(creds);
447 trigger->creds = *creds;
448 }
449
450 enum 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
472 end:
473 return ret;
474 }
475
476 enum 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
495 end:
496 return ret;
497 }
This page took 0.042693 seconds and 4 git commands to generate.