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