c5efaa3198b6aa5cfaea5c038e491ccfee92cc89
[lttng-tools.git] / src / common / tracker.cpp
1 /*
2 * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
3 * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 *
5 * SPDX-License-Identifier: LGPL-2.1-only
6 *
7 */
8
9 #include <lttng/domain.h>
10 #include <lttng/lttng-error.h>
11 #include <lttng/tracker.h>
12
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
21 #include <type_traits>
22
23 struct process_attr_tracker_values_comm_header {
24 uint32_t count;
25 };
26
27 struct 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) \
38 ((as_type)(std::is_signed<as_type>::value ? (value_ptr)->u._signed : \
39 (value_ptr)->u._unsigned))
40
41 #define SET_INTEGRAL_COMM_VALUE(comm_value, val) \
42 if (std::is_signed<typeof(val)>::value) { \
43 (comm_value)->u._signed = \
44 (typeof((comm_value)->u._signed)) val; \
45 } else { \
46 (comm_value)->u._unsigned = \
47 (typeof((comm_value)->u._unsigned)) val; \
48 }
49
50 static 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;
55 }
56
57 static inline bool is_value_type_name(
58 enum lttng_process_attr_value_type value_type)
59 {
60 return value_type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ||
61 value_type == LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME;
62 }
63
64 enum 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)
71 {
72 char *name = NULL;
73 enum lttng_error_code ret = LTTNG_OK;
74 struct process_attr_value *value = (process_attr_value *) zmalloc(sizeof(*value));
75
76 if (!value) {
77 ret = LTTNG_ERR_NOMEM;
78 goto error;
79 }
80
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;
89 goto error;
90 }
91 }
92
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 }
98
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 }
105
106 /* Only expect a payload for name value types. */
107 if (is_value_type_name(value_type) &&
108 (!value_view || value_view->size == 0)) {
109 ret = LTTNG_ERR_INVALID_PROTOCOL;
110 goto error;
111 } else if (!is_value_type_name(value_type) && value_view &&
112 value_view->size != 0) {
113 ret = LTTNG_ERR_INVALID_PROTOCOL;
114 goto error;
115 }
116
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;
176 }
177
178 *_value = value;
179 value = NULL;
180 free(name);
181 return LTTNG_OK;
182 error:
183 free(name);
184 process_attr_value_destroy(value);
185 return ret;
186 }
187
188 const char *lttng_process_attr_to_string(enum lttng_process_attr process_attr)
189 {
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";
205 }
206 }
207
208 static void process_attr_tracker_value_destructor(void *ptr)
209 {
210 struct process_attr_value *value = (typeof(value)) ptr;
211
212 process_attr_value_destroy(value);
213 }
214
215 struct lttng_process_attr_values *lttng_process_attr_values_create(void)
216 {
217 struct lttng_process_attr_values *values = (lttng_process_attr_values *) zmalloc(sizeof(*values));
218
219 if (!values) {
220 goto end;
221 }
222
223 lttng_dynamic_pointer_array_init(
224 &values->array, process_attr_tracker_value_destructor);
225 end:
226 return values;
227 }
228
229 unsigned int _lttng_process_attr_values_get_count(
230 const struct lttng_process_attr_values *values)
231 {
232 return (unsigned int) lttng_dynamic_pointer_array_get_count(
233 &values->array);
234 }
235
236 const struct process_attr_value *lttng_process_attr_tracker_values_get_at_index(
237 const struct lttng_process_attr_values *values,
238 unsigned int index)
239 {
240 return (process_attr_value *) lttng_dynamic_pointer_array_get_pointer(&values->array, index);
241 }
242
243 static
244 int 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,
250 };
251 const char *name = NULL;
252
253 switch (value->type) {
254 case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID:
255 SET_INTEGRAL_COMM_VALUE(
256 &value_comm.value.integral, value->value.pid);
257 break;
258 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
259 SET_INTEGRAL_COMM_VALUE(
260 &value_comm.value.integral, value->value.uid);
261 break;
262 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
263 SET_INTEGRAL_COMM_VALUE(
264 &value_comm.value.integral, value->value.gid);
265 break;
266 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
267 name = value->value.user_name;
268 break;
269 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
270 name = value->value.group_name;
271 break;
272 default:
273 abort();
274 }
275
276 if (name) {
277 value_comm.value.name_len = strlen(name) + 1;
278 }
279
280 ret = lttng_dynamic_buffer_append(
281 buffer, &value_comm, sizeof(value_comm));
282 if (ret) {
283 goto end;
284 }
285
286 if (name) {
287 ret = lttng_dynamic_buffer_append(
288 buffer, name, value_comm.value.name_len);
289 }
290 end:
291 return ret;
292 }
293
294 int lttng_process_attr_values_serialize(
295 const struct lttng_process_attr_values *values,
296 struct lttng_dynamic_buffer *buffer)
297 {
298 int ret;
299 unsigned int count, i;
300 struct process_attr_tracker_values_comm_header header = {};
301
302 count = _lttng_process_attr_values_get_count(values);
303 header.count = (uint32_t) count;
304
305 ret = lttng_dynamic_buffer_append(buffer, &header, sizeof(header));
306 if (ret) {
307 goto end;
308 }
309
310 for (i = 0; i < count; i++) {
311 const struct process_attr_value *value =
312 lttng_process_attr_tracker_values_get_at_index(
313 values, i);
314
315 ret = process_attr_tracker_value_serialize(value, buffer);
316 if (ret) {
317 goto end;
318 }
319 }
320 end:
321 return ret;
322 }
323
324 ssize_t lttng_process_attr_values_create_from_buffer(
325 enum lttng_domain_type domain,
326 enum lttng_process_attr process_attr,
327 const struct lttng_buffer_view *buffer_view,
328 struct lttng_process_attr_values **_values)
329 {
330 ssize_t offset;
331 unsigned int i;
332 struct lttng_process_attr_values *values;
333 struct lttng_buffer_view header_view;
334 const struct process_attr_tracker_values_comm_header *header;
335
336 values = lttng_process_attr_values_create();
337 if (!values) {
338 goto error;
339 }
340
341 header_view = lttng_buffer_view_from_view(
342 buffer_view, 0, sizeof(*header));
343 if (!lttng_buffer_view_is_valid(&header_view)) {
344 goto error;
345 }
346
347 offset = header_view.size;
348 header = (typeof(header)) header_view.data;
349
350 /*
351 * Check that the number of values is not absurdly large with respect to
352 * the received buffer's size.
353 */
354 if (buffer_view->size <
355 header->count * sizeof(struct process_attr_tracker_value_comm)) {
356 goto error;
357 }
358 for (i = 0; i < (unsigned int) header->count; i++) {
359 int ret;
360 enum lttng_error_code ret_code;
361 const struct process_attr_tracker_value_comm *value_comm;
362 struct process_attr_value *value;
363 enum lttng_process_attr_value_type type;
364 struct lttng_buffer_view value_view;
365 struct lttng_buffer_view value_name_view = {};
366
367 value_view = lttng_buffer_view_from_view(
368 buffer_view, offset, sizeof(*value_comm));
369 if (!lttng_buffer_view_is_valid(&value_view)) {
370 goto error;
371 }
372
373 offset += value_view.size;
374 value_comm = (typeof(value_comm)) value_view.data;
375 type = (typeof(type)) value_comm->type;
376
377 if (is_value_type_name(type)) {
378 value_name_view = lttng_buffer_view_from_view(
379 buffer_view, offset,
380 value_comm->value.name_len);
381 if (!lttng_buffer_view_is_valid(&value_name_view)) {
382 goto error;
383 }
384
385 offset += value_name_view.size;
386 }
387
388 ret_code = process_attr_value_from_comm(domain, process_attr,
389 type, &value_comm->value.integral,
390 &value_name_view, &value);
391 if (ret_code != LTTNG_OK) {
392 goto error;
393 }
394
395 ret = lttng_dynamic_pointer_array_add_pointer(
396 &values->array, value);
397 if (ret) {
398 process_attr_value_destroy(value);
399 goto error;
400 }
401 }
402
403 *_values = values;
404 return offset;
405 error:
406 lttng_process_attr_values_destroy(values);
407 return -1;
408 }
409
410 void lttng_process_attr_values_destroy(struct lttng_process_attr_values *values)
411 {
412 if (!values) {
413 return;
414 }
415 lttng_dynamic_pointer_array_reset(&values->array);
416 free(values);
417 }
418
419 struct process_attr_value *process_attr_value_copy(
420 const struct process_attr_value *value)
421 {
422 struct process_attr_value *new_value = NULL;
423
424 if (!value) {
425 goto end;
426 }
427
428 new_value = (process_attr_value *) zmalloc(sizeof(*new_value));
429 if (!new_value) {
430 goto end;
431 }
432 if (is_value_type_name(value->type)) {
433 const char *src =
434 value->type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ?
435 value->value.user_name :
436 value->value.group_name;
437 char **dst = value->type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ?
438 &new_value->value.user_name :
439 &new_value->value.group_name;
440
441 new_value->type = value->type;
442 *dst = strdup(src);
443 if (!*dst) {
444 goto error;
445 }
446 } else {
447 *new_value = *value;
448 }
449 end:
450 return new_value;
451 error:
452 free(new_value);
453 return NULL;
454 }
455
456 unsigned long process_attr_value_hash(const struct process_attr_value *a)
457 {
458 unsigned long hash = hash_key_ulong((void *) a->type, lttng_ht_seed);
459
460 switch (a->type) {
461 case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID:
462 hash ^= hash_key_ulong((void *) (unsigned long) a->value.pid,
463 lttng_ht_seed);
464 break;
465 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
466 hash ^= hash_key_ulong((void *) (unsigned long) a->value.uid,
467 lttng_ht_seed);
468 break;
469 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
470 hash ^= hash_key_ulong((void *) (unsigned long) a->value.gid,
471 lttng_ht_seed);
472 break;
473 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
474 hash ^= hash_key_str(a->value.user_name, lttng_ht_seed);
475 break;
476 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
477 hash ^= hash_key_str(a->value.group_name, lttng_ht_seed);
478 break;
479 default:
480 abort();
481 }
482
483 return hash;
484 }
485
486 bool process_attr_tracker_value_equal(const struct process_attr_value *a,
487 const struct process_attr_value *b)
488 {
489 if (a->type != b->type) {
490 return false;
491 }
492 switch (a->type) {
493 case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID:
494 return a->value.pid == b->value.pid;
495 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
496 return a->value.uid == b->value.uid;
497 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
498 return a->value.gid == b->value.gid;
499 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
500 return !strcmp(a->value.user_name, b->value.user_name);
501 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
502 return !strcmp(a->value.group_name, b->value.group_name);
503 default:
504 abort();
505 }
506 }
507
508 void process_attr_value_destroy(struct process_attr_value *value)
509 {
510 if (!value) {
511 return;
512 }
513 if (is_value_type_name(value->type)) {
514 free(value->type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ?
515 value->value.user_name :
516 value->value.group_name);
517 }
518 free(value);
519 }
This page took 0.038075 seconds and 3 git commands to generate.