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