liblttng-ctl: use export list to define exported symbols
[lttng-tools.git] / src / common / tracker.c
CommitLineData
2d97a006 1/*
4942c256 2 * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
159b042f 3 * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
2d97a006 4 *
ab5be9fa 5 * SPDX-License-Identifier: LGPL-2.1-only
2d97a006 6 *
2d97a006
JR
7 */
8
159b042f
JG
9#include <lttng/domain.h>
10#include <lttng/lttng-error.h>
11#include <lttng/tracker.h>
2d97a006 12
159b042f
JG
13#include <common/dynamic-array.h>
14#include <common/error.h>
15#include <common/hashtable/hashtable.h>
16#include <common/hashtable/utils.h>
17#include <common/tracker.h>
18
19#include <stdbool.h>
20
21struct process_attr_tracker_values_comm_header {
22 uint32_t count;
23};
24
25struct process_attr_tracker_value_comm {
26 /* enum lttng_process_attr_value_type */
27 int32_t type;
28 union {
29 struct process_attr_integral_value_comm integral;
30 /* Includes the '\0' terminator. */
31 uint32_t name_len;
32 } value;
33};
34
35#define GET_INTEGRAL_COMM_VALUE(value_ptr, as_type) \
36 ((as_type)(is_signed(as_type) ? (value_ptr)->u._signed : \
37 (value_ptr)->u._unsigned))
38
39#define SET_INTEGRAL_COMM_VALUE(comm_value, value) \
40 if (is_signed(typeof(value))) { \
41 (comm_value)->u._signed = \
42 (typeof((comm_value)->u._signed)) value; \
43 } else { \
44 (comm_value)->u._unsigned = \
45 (typeof((comm_value)->u._unsigned)) value; \
2d97a006
JR
46 }
47
159b042f
JG
48static inline bool is_virtual_process_attr(enum lttng_process_attr process_attr)
49{
50 return process_attr == LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID ||
51 process_attr == LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID ||
52 process_attr == LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID;
2d97a006
JR
53}
54
159b042f
JG
55static inline bool is_value_type_name(
56 enum lttng_process_attr_value_type value_type)
2d97a006 57{
159b042f
JG
58 return value_type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ||
59 value_type == LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME;
2d97a006
JR
60}
61
159b042f
JG
62enum lttng_error_code process_attr_value_from_comm(
63 enum lttng_domain_type domain,
64 enum lttng_process_attr process_attr,
65 enum lttng_process_attr_value_type value_type,
66 const struct process_attr_integral_value_comm *integral_value,
67 const struct lttng_buffer_view *value_view,
68 struct process_attr_value **_value)
2d97a006 69{
159b042f
JG
70 char *name = NULL;
71 enum lttng_error_code ret = LTTNG_OK;
72 struct process_attr_value *value = zmalloc(sizeof(*value));
2d97a006 73
159b042f
JG
74 if (!value) {
75 ret = LTTNG_ERR_NOMEM;
2d97a006
JR
76 goto error;
77 }
78
159b042f
JG
79 if (value_view && value_view->size > 0) {
80 if (value_view->data[value_view->size - 1] != '\0') {
81 ret = LTTNG_ERR_INVALID;
82 goto error;
83 }
84 name = strdup(value_view->data);
85 if (!name) {
86 ret = LTTNG_ERR_NOMEM;
74675e31 87 goto error;
159b042f
JG
88 }
89 }
2d97a006 90
159b042f
JG
91 if (domain != LTTNG_DOMAIN_UST && domain != LTTNG_DOMAIN_KERNEL) {
92 ERR("Only the user space and kernel space domains may be specified to configure process attribute trackers");
93 ret = LTTNG_ERR_UNSUPPORTED_DOMAIN;
94 goto error;
95 }
2d97a006 96
159b042f
JG
97 if (!is_virtual_process_attr(process_attr) &&
98 domain != LTTNG_DOMAIN_KERNEL) {
99 ERR("Non-virtual process attributes can only be used in the kernel domain");
100 ret = LTTNG_ERR_UNSUPPORTED_DOMAIN;
101 goto error;
102 }
2d97a006 103
159b042f 104 /* Only expect a payload for name value types. */
b78dab17
JG
105 if (is_value_type_name(value_type) &&
106 (!value_view || value_view->size == 0)) {
159b042f
JG
107 ret = LTTNG_ERR_INVALID_PROTOCOL;
108 goto error;
1ad5cb59
JG
109 } else if (!is_value_type_name(value_type) && value_view &&
110 value_view->size != 0) {
159b042f
JG
111 ret = LTTNG_ERR_INVALID_PROTOCOL;
112 goto error;
2d97a006
JR
113 }
114
159b042f
JG
115 value->type = value_type;
116 switch (process_attr) {
117 case LTTNG_PROCESS_ATTR_PROCESS_ID:
118 case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
119 if (value_type != LTTNG_PROCESS_ATTR_VALUE_TYPE_PID) {
120 ERR("Invalid value type used for process ID process attribute");
121 ret = LTTNG_ERR_INVALID;
122 goto error;
123 }
124 value->value.pid =
125 GET_INTEGRAL_COMM_VALUE(integral_value, pid_t);
126 break;
127 case LTTNG_PROCESS_ATTR_USER_ID:
128 case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
129 switch (value_type) {
130 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
131 value->value.uid = GET_INTEGRAL_COMM_VALUE(
132 integral_value, uid_t);
133 break;
134 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
135 if (!name) {
136 ret = LTTNG_ERR_INVALID;
137 goto error;
138 }
139
140 value->value.user_name = name;
141 name = NULL;
142 break;
143 default:
144 ERR("Invalid value type used for user ID process attribute");
145 ret = LTTNG_ERR_INVALID;
146 goto error;
147 }
148 break;
149 case LTTNG_PROCESS_ATTR_GROUP_ID:
150 case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
151 switch (value_type) {
152 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
153 value->value.gid = GET_INTEGRAL_COMM_VALUE(
154 integral_value, gid_t);
155 break;
156 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
157 if (!name) {
158 ret = LTTNG_ERR_INVALID;
159 goto error;
160 }
161
162 value->value.group_name = name;
163 name = NULL;
164 break;
165 default:
166 ERR("Invalid value type used for group ID process attribute");
167 ret = LTTNG_ERR_INVALID;
168 goto error;
169 }
170 break;
171 default:
172 ret = LTTNG_ERR_INVALID_PROTOCOL;
173 goto error;
2d97a006
JR
174 }
175
159b042f
JG
176 *_value = value;
177 value = NULL;
d4e37173 178 free(name);
159b042f
JG
179 return LTTNG_OK;
180error:
181 free(name);
182 process_attr_value_destroy(value);
183 return ret;
2d97a006
JR
184}
185
159b042f 186const char *lttng_process_attr_to_string(enum lttng_process_attr process_attr)
2d97a006 187{
159b042f
JG
188 switch (process_attr) {
189 case LTTNG_PROCESS_ATTR_PROCESS_ID:
190 return "process ID";
191 case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
192 return "virtual process ID";
193 case LTTNG_PROCESS_ATTR_USER_ID:
194 return "user ID";
195 case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
196 return "virtual user ID";
197 case LTTNG_PROCESS_ATTR_GROUP_ID:
198 return "group ID";
199 case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
200 return "virtual group ID";
201 default:
202 return "unknown process attribute";
2d97a006 203 }
2d97a006
JR
204}
205
159b042f 206static void process_attr_tracker_value_destructor(void *ptr)
2d97a006 207{
159b042f
JG
208 struct process_attr_value *value = (typeof(value)) ptr;
209
210 process_attr_value_destroy(value);
2d97a006
JR
211}
212
159b042f 213struct lttng_process_attr_values *lttng_process_attr_values_create(void)
2d97a006 214{
159b042f 215 struct lttng_process_attr_values *values = zmalloc(sizeof(*values));
2d97a006 216
159b042f
JG
217 if (!values) {
218 goto end;
2d97a006
JR
219 }
220
159b042f
JG
221 lttng_dynamic_pointer_array_init(
222 &values->array, process_attr_tracker_value_destructor);
223end:
224 return values;
2d97a006
JR
225}
226
159b042f
JG
227unsigned int _lttng_process_attr_values_get_count(
228 const struct lttng_process_attr_values *values)
2d97a006 229{
159b042f
JG
230 return (unsigned int) lttng_dynamic_pointer_array_get_count(
231 &values->array);
2d97a006
JR
232}
233
159b042f
JG
234const struct process_attr_value *lttng_process_attr_tracker_values_get_at_index(
235 const struct lttng_process_attr_values *values,
236 unsigned int index)
2d97a006 237{
159b042f
JG
238 return lttng_dynamic_pointer_array_get_pointer(&values->array, index);
239}
2d97a006 240
159b042f
JG
241static
242int process_attr_tracker_value_serialize(const struct process_attr_value *value,
243 struct lttng_dynamic_buffer *buffer)
244{
245 int ret;
246 struct process_attr_tracker_value_comm value_comm = {
247 .type = (int32_t) value->type,
248 };
249 const char *name = NULL;
250
251 switch (value->type) {
252 case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID:
253 SET_INTEGRAL_COMM_VALUE(
254 &value_comm.value.integral, value->value.pid);
2d97a006 255 break;
159b042f
JG
256 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
257 SET_INTEGRAL_COMM_VALUE(
258 &value_comm.value.integral, value->value.uid);
2d97a006 259 break;
159b042f
JG
260 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
261 SET_INTEGRAL_COMM_VALUE(
262 &value_comm.value.integral, value->value.gid);
2d97a006 263 break;
159b042f
JG
264 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
265 name = value->value.user_name;
2d97a006 266 break;
159b042f
JG
267 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
268 name = value->value.group_name;
269 break;
270 default:
271 abort();
2d97a006
JR
272 }
273
159b042f
JG
274 if (name) {
275 value_comm.value.name_len = strlen(name) + 1;
a7a533cd 276 }
159b042f
JG
277
278 ret = lttng_dynamic_buffer_append(
279 buffer, &value_comm, sizeof(value_comm));
280 if (ret) {
281 goto end;
282 }
283
284 if (name) {
285 ret = lttng_dynamic_buffer_append(
286 buffer, name, value_comm.value.name_len);
287 }
288end:
a7a533cd
JR
289 return ret;
290}
291
159b042f
JG
292int lttng_process_attr_values_serialize(
293 const struct lttng_process_attr_values *values,
294 struct lttng_dynamic_buffer *buffer)
a7a533cd
JR
295{
296 int ret;
159b042f
JG
297 unsigned int count, i;
298 struct process_attr_tracker_values_comm_header header = {};
a7a533cd 299
159b042f
JG
300 count = _lttng_process_attr_values_get_count(values);
301 header.count = (uint32_t) count;
a7a533cd 302
159b042f 303 ret = lttng_dynamic_buffer_append(buffer, &header, sizeof(header));
a7a533cd 304 if (ret) {
159b042f 305 goto end;
2d97a006
JR
306 }
307
159b042f
JG
308 for (i = 0; i < count; i++) {
309 const struct process_attr_value *value =
310 lttng_process_attr_tracker_values_get_at_index(
311 values, i);
2d97a006 312
159b042f
JG
313 ret = process_attr_tracker_value_serialize(value, buffer);
314 if (ret) {
315 goto end;
316 }
2d97a006 317 }
159b042f
JG
318end:
319 return ret;
2d97a006 320}
a7a533cd 321
159b042f
JG
322ssize_t lttng_process_attr_values_create_from_buffer(
323 enum lttng_domain_type domain,
324 enum lttng_process_attr process_attr,
325 const struct lttng_buffer_view *buffer_view,
326 struct lttng_process_attr_values **_values)
a7a533cd 327{
159b042f
JG
328 ssize_t offset;
329 unsigned int i;
330 struct lttng_process_attr_values *values;
331 struct lttng_buffer_view header_view;
332 const struct process_attr_tracker_values_comm_header *header;
a7a533cd 333
159b042f
JG
334 values = lttng_process_attr_values_create();
335 if (!values) {
a7a533cd
JR
336 goto error;
337 }
338
159b042f
JG
339 header_view = lttng_buffer_view_from_view(
340 buffer_view, 0, sizeof(*header));
3e6e0df2 341 if (!lttng_buffer_view_is_valid(&header_view)) {
a7a533cd
JR
342 goto error;
343 }
3e6e0df2 344
159b042f
JG
345 offset = header_view.size;
346 header = (typeof(header)) header_view.data;
347
348 /*
349 * Check that the number of values is not absurdly large with respect to
350 * the received buffer's size.
351 */
352 if (buffer_view->size <
353 header->count * sizeof(struct process_attr_tracker_value_comm)) {
354 goto error;
355 }
356 for (i = 0; i < (unsigned int) header->count; i++) {
357 int ret;
358 enum lttng_error_code ret_code;
359 const struct process_attr_tracker_value_comm *value_comm;
360 struct process_attr_value *value;
361 enum lttng_process_attr_value_type type;
362 struct lttng_buffer_view value_view;
363 struct lttng_buffer_view value_name_view = {};
364
365 value_view = lttng_buffer_view_from_view(
366 buffer_view, offset, sizeof(*value_comm));
3e6e0df2 367 if (!lttng_buffer_view_is_valid(&value_view)) {
159b042f
JG
368 goto error;
369 }
a7a533cd 370
159b042f
JG
371 offset += value_view.size;
372 value_comm = (typeof(value_comm)) value_view.data;
373 type = (typeof(type)) value_comm->type;
a7a533cd 374
159b042f
JG
375 if (is_value_type_name(type)) {
376 value_name_view = lttng_buffer_view_from_view(
377 buffer_view, offset,
378 value_comm->value.name_len);
3e6e0df2
JG
379 if (!lttng_buffer_view_is_valid(&value_name_view)) {
380 goto error;
381 }
382
159b042f
JG
383 offset += value_name_view.size;
384 }
3e6e0df2 385
159b042f
JG
386 ret_code = process_attr_value_from_comm(domain, process_attr,
387 type, &value_comm->value.integral,
388 &value_name_view, &value);
389 if (ret_code != LTTNG_OK) {
390 goto error;
391 }
a7a533cd 392
159b042f
JG
393 ret = lttng_dynamic_pointer_array_add_pointer(
394 &values->array, value);
395 if (ret) {
396 process_attr_value_destroy(value);
397 goto error;
398 }
a7a533cd
JR
399 }
400
159b042f
JG
401 *_values = values;
402 return offset;
403error:
404 lttng_process_attr_values_destroy(values);
405 return -1;
a7a533cd
JR
406}
407
159b042f 408void lttng_process_attr_values_destroy(struct lttng_process_attr_values *values)
a7a533cd 409{
159b042f
JG
410 if (!values) {
411 return;
412 }
413 lttng_dynamic_pointer_array_reset(&values->array);
414 free(values);
a7a533cd
JR
415}
416
159b042f
JG
417struct process_attr_value *process_attr_value_copy(
418 const struct process_attr_value *value)
a7a533cd 419{
159b042f 420 struct process_attr_value *new_value = NULL;
e283e4a0 421
159b042f 422 if (!value) {
e283e4a0
JR
423 goto end;
424 }
425
159b042f
JG
426 new_value = zmalloc(sizeof(*new_value));
427 if (!new_value) {
428 goto end;
429 }
430 if (is_value_type_name(value->type)) {
431 const char *src =
432 value->type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ?
433 value->value.user_name :
434 value->value.group_name;
435 char **dst = value->type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ?
436 &new_value->value.user_name :
437 &new_value->value.group_name;
438
439 new_value->type = value->type;
440 *dst = strdup(src);
441 if (!*dst) {
442 goto error;
443 }
444 } else {
445 *new_value = *value;
446 }
e283e4a0 447end:
159b042f
JG
448 return new_value;
449error:
450 free(new_value);
451 return NULL;
a7a533cd
JR
452}
453
159b042f 454unsigned long process_attr_value_hash(const struct process_attr_value *a)
a7a533cd 455{
159b042f 456 unsigned long hash = hash_key_ulong((void *) a->type, lttng_ht_seed);
9df6c82a 457
159b042f
JG
458 switch (a->type) {
459 case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID:
460 hash ^= hash_key_ulong((void *) (unsigned long) a->value.pid,
461 lttng_ht_seed);
462 break;
463 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
464 hash ^= hash_key_ulong((void *) (unsigned long) a->value.uid,
465 lttng_ht_seed);
466 break;
467 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
468 hash ^= hash_key_ulong((void *) (unsigned long) a->value.gid,
469 lttng_ht_seed);
470 break;
471 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
472 hash ^= hash_key_str(a->value.user_name, lttng_ht_seed);
473 break;
474 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
475 hash ^= hash_key_str(a->value.group_name, lttng_ht_seed);
476 break;
477 default:
478 abort();
a7a533cd
JR
479 }
480
159b042f 481 return hash;
a7a533cd 482}
f19f5c96 483
159b042f
JG
484bool process_attr_tracker_value_equal(const struct process_attr_value *a,
485 const struct process_attr_value *b)
f19f5c96 486{
159b042f
JG
487 if (a->type != b->type) {
488 return false;
f19f5c96 489 }
159b042f
JG
490 switch (a->type) {
491 case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID:
492 return a->value.pid == b->value.pid;
493 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
494 return a->value.uid == b->value.uid;
495 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
496 return a->value.gid == b->value.gid;
497 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
498 return !strcmp(a->value.user_name, b->value.user_name);
499 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
500 return !strcmp(a->value.group_name, b->value.group_name);
501 default:
502 abort();
503 }
504}
f19f5c96 505
159b042f
JG
506void process_attr_value_destroy(struct process_attr_value *value)
507{
508 if (!value) {
509 return;
f19f5c96 510 }
159b042f
JG
511 if (is_value_type_name(value->type)) {
512 free(value->type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ?
513 value->value.user_name :
514 value->value.group_name);
515 }
516 free(value);
f19f5c96 517}
This page took 0.052017 seconds and 4 git commands to generate.