Refactor: lttng-ctl: follow terminology of the tracker documentation
[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
62LTTNG_HIDDEN
63enum lttng_error_code process_attr_value_from_comm(
64 enum lttng_domain_type domain,
65 enum lttng_process_attr process_attr,
66 enum lttng_process_attr_value_type value_type,
67 const struct process_attr_integral_value_comm *integral_value,
68 const struct lttng_buffer_view *value_view,
69 struct process_attr_value **_value)
2d97a006 70{
159b042f
JG
71 char *name = NULL;
72 enum lttng_error_code ret = LTTNG_OK;
73 struct process_attr_value *value = zmalloc(sizeof(*value));
2d97a006 74
159b042f
JG
75 if (!value) {
76 ret = LTTNG_ERR_NOMEM;
2d97a006
JR
77 goto error;
78 }
79
159b042f
JG
80 if (value_view && value_view->size > 0) {
81 if (value_view->data[value_view->size - 1] != '\0') {
82 ret = LTTNG_ERR_INVALID;
83 goto error;
84 }
85 name = strdup(value_view->data);
86 if (!name) {
87 ret = LTTNG_ERR_NOMEM;
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
JG
104 /* Only expect a payload for name value types. */
105 if (is_value_type_name(value_type) && value_view->size == 0) {
106 ret = LTTNG_ERR_INVALID_PROTOCOL;
107 goto error;
108 } else if (!is_value_type_name(value_type) && value_view->size != 0) {
109 ret = LTTNG_ERR_INVALID_PROTOCOL;
110 goto error;
2d97a006
JR
111 }
112
159b042f
JG
113 value->type = value_type;
114 switch (process_attr) {
115 case LTTNG_PROCESS_ATTR_PROCESS_ID:
116 case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
117 if (value_type != LTTNG_PROCESS_ATTR_VALUE_TYPE_PID) {
118 ERR("Invalid value type used for process ID process attribute");
119 ret = LTTNG_ERR_INVALID;
120 goto error;
121 }
122 value->value.pid =
123 GET_INTEGRAL_COMM_VALUE(integral_value, pid_t);
124 break;
125 case LTTNG_PROCESS_ATTR_USER_ID:
126 case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
127 switch (value_type) {
128 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
129 value->value.uid = GET_INTEGRAL_COMM_VALUE(
130 integral_value, uid_t);
131 break;
132 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
133 if (!name) {
134 ret = LTTNG_ERR_INVALID;
135 goto error;
136 }
137
138 value->value.user_name = name;
139 name = NULL;
140 break;
141 default:
142 ERR("Invalid value type used for user ID process attribute");
143 ret = LTTNG_ERR_INVALID;
144 goto error;
145 }
146 break;
147 case LTTNG_PROCESS_ATTR_GROUP_ID:
148 case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
149 switch (value_type) {
150 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
151 value->value.gid = GET_INTEGRAL_COMM_VALUE(
152 integral_value, gid_t);
153 break;
154 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
155 if (!name) {
156 ret = LTTNG_ERR_INVALID;
157 goto error;
158 }
159
160 value->value.group_name = name;
161 name = NULL;
162 break;
163 default:
164 ERR("Invalid value type used for group ID process attribute");
165 ret = LTTNG_ERR_INVALID;
166 goto error;
167 }
168 break;
169 default:
170 ret = LTTNG_ERR_INVALID_PROTOCOL;
171 goto error;
2d97a006
JR
172 }
173
159b042f
JG
174 *_value = value;
175 value = NULL;
176 return LTTNG_OK;
177error:
178 free(name);
179 process_attr_value_destroy(value);
180 return ret;
2d97a006
JR
181}
182
159b042f
JG
183LTTNG_HIDDEN
184const char *lttng_process_attr_to_string(enum lttng_process_attr process_attr)
2d97a006 185{
159b042f
JG
186 switch (process_attr) {
187 case LTTNG_PROCESS_ATTR_PROCESS_ID:
188 return "process ID";
189 case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
190 return "virtual process ID";
191 case LTTNG_PROCESS_ATTR_USER_ID:
192 return "user ID";
193 case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
194 return "virtual user ID";
195 case LTTNG_PROCESS_ATTR_GROUP_ID:
196 return "group ID";
197 case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
198 return "virtual group ID";
199 default:
200 return "unknown process attribute";
2d97a006 201 }
2d97a006
JR
202}
203
159b042f 204static void process_attr_tracker_value_destructor(void *ptr)
2d97a006 205{
159b042f
JG
206 struct process_attr_value *value = (typeof(value)) ptr;
207
208 process_attr_value_destroy(value);
2d97a006
JR
209}
210
159b042f
JG
211LTTNG_HIDDEN
212struct lttng_process_attr_values *lttng_process_attr_values_create(void)
2d97a006 213{
159b042f 214 struct lttng_process_attr_values *values = zmalloc(sizeof(*values));
2d97a006 215
159b042f
JG
216 if (!values) {
217 goto end;
2d97a006
JR
218 }
219
159b042f
JG
220 lttng_dynamic_pointer_array_init(
221 &values->array, process_attr_tracker_value_destructor);
222end:
223 return values;
2d97a006
JR
224}
225
159b042f
JG
226LTTNG_HIDDEN
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
234LTTNG_HIDDEN
235const struct process_attr_value *lttng_process_attr_tracker_values_get_at_index(
236 const struct lttng_process_attr_values *values,
237 unsigned int index)
2d97a006 238{
159b042f
JG
239 return lttng_dynamic_pointer_array_get_pointer(&values->array, index);
240}
2d97a006 241
159b042f
JG
242static
243int process_attr_tracker_value_serialize(const struct process_attr_value *value,
244 struct lttng_dynamic_buffer *buffer)
245{
246 int ret;
247 struct process_attr_tracker_value_comm value_comm = {
248 .type = (int32_t) value->type,
249 };
250 const char *name = NULL;
251
252 switch (value->type) {
253 case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID:
254 SET_INTEGRAL_COMM_VALUE(
255 &value_comm.value.integral, value->value.pid);
2d97a006 256 break;
159b042f
JG
257 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
258 SET_INTEGRAL_COMM_VALUE(
259 &value_comm.value.integral, value->value.uid);
2d97a006 260 break;
159b042f
JG
261 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
262 SET_INTEGRAL_COMM_VALUE(
263 &value_comm.value.integral, value->value.gid);
2d97a006 264 break;
159b042f
JG
265 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
266 name = value->value.user_name;
2d97a006 267 break;
159b042f
JG
268 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
269 name = value->value.group_name;
270 break;
271 default:
272 abort();
2d97a006
JR
273 }
274
159b042f
JG
275 if (name) {
276 value_comm.value.name_len = strlen(name) + 1;
a7a533cd 277 }
159b042f
JG
278
279 ret = lttng_dynamic_buffer_append(
280 buffer, &value_comm, sizeof(value_comm));
281 if (ret) {
282 goto end;
283 }
284
285 if (name) {
286 ret = lttng_dynamic_buffer_append(
287 buffer, name, value_comm.value.name_len);
288 }
289end:
a7a533cd
JR
290 return ret;
291}
292
159b042f
JG
293LTTNG_HIDDEN
294int lttng_process_attr_values_serialize(
295 const struct lttng_process_attr_values *values,
296 struct lttng_dynamic_buffer *buffer)
a7a533cd
JR
297{
298 int ret;
159b042f
JG
299 unsigned int count, i;
300 struct process_attr_tracker_values_comm_header header = {};
a7a533cd 301
159b042f
JG
302 count = _lttng_process_attr_values_get_count(values);
303 header.count = (uint32_t) count;
a7a533cd 304
159b042f 305 ret = lttng_dynamic_buffer_append(buffer, &header, sizeof(header));
a7a533cd 306 if (ret) {
159b042f 307 goto end;
2d97a006
JR
308 }
309
159b042f
JG
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);
2d97a006 314
159b042f
JG
315 ret = process_attr_tracker_value_serialize(value, buffer);
316 if (ret) {
317 goto end;
318 }
2d97a006 319 }
159b042f
JG
320end:
321 return ret;
2d97a006 322}
a7a533cd 323
159b042f
JG
324LTTNG_HIDDEN
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));
344 if (!header_view.data) {
a7a533cd
JR
345 goto error;
346 }
159b042f
JG
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 (!value_view.data) {
370 goto error;
371 }
a7a533cd 372
159b042f
JG
373 offset += value_view.size;
374 value_comm = (typeof(value_comm)) value_view.data;
375 type = (typeof(type)) value_comm->type;
a7a533cd 376
159b042f
JG
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 offset += value_name_view.size;
382 }
383 ret_code = process_attr_value_from_comm(domain, process_attr,
384 type, &value_comm->value.integral,
385 &value_name_view, &value);
386 if (ret_code != LTTNG_OK) {
387 goto error;
388 }
a7a533cd 389
159b042f
JG
390 ret = lttng_dynamic_pointer_array_add_pointer(
391 &values->array, value);
392 if (ret) {
393 process_attr_value_destroy(value);
394 goto error;
395 }
a7a533cd
JR
396 }
397
159b042f
JG
398 *_values = values;
399 return offset;
400error:
401 lttng_process_attr_values_destroy(values);
402 return -1;
a7a533cd
JR
403}
404
159b042f
JG
405LTTNG_HIDDEN
406void lttng_process_attr_values_destroy(struct lttng_process_attr_values *values)
a7a533cd 407{
159b042f
JG
408 if (!values) {
409 return;
410 }
411 lttng_dynamic_pointer_array_reset(&values->array);
412 free(values);
a7a533cd
JR
413}
414
159b042f
JG
415LTTNG_HIDDEN
416struct process_attr_value *process_attr_value_copy(
417 const struct process_attr_value *value)
a7a533cd 418{
159b042f 419 struct process_attr_value *new_value = NULL;
e283e4a0 420
159b042f 421 if (!value) {
e283e4a0
JR
422 goto end;
423 }
424
159b042f
JG
425 new_value = zmalloc(sizeof(*new_value));
426 if (!new_value) {
427 goto end;
428 }
429 if (is_value_type_name(value->type)) {
430 const char *src =
431 value->type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ?
432 value->value.user_name :
433 value->value.group_name;
434 char **dst = value->type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ?
435 &new_value->value.user_name :
436 &new_value->value.group_name;
437
438 new_value->type = value->type;
439 *dst = strdup(src);
440 if (!*dst) {
441 goto error;
442 }
443 } else {
444 *new_value = *value;
445 }
e283e4a0 446end:
159b042f
JG
447 return new_value;
448error:
449 free(new_value);
450 return NULL;
a7a533cd
JR
451}
452
159b042f
JG
453LTTNG_HIDDEN
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
484LTTNG_HIDDEN
485bool process_attr_tracker_value_equal(const struct process_attr_value *a,
486 const struct process_attr_value *b)
f19f5c96 487{
159b042f
JG
488 if (a->type != b->type) {
489 return false;
f19f5c96 490 }
159b042f
JG
491 switch (a->type) {
492 case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID:
493 return a->value.pid == b->value.pid;
494 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
495 return a->value.uid == b->value.uid;
496 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
497 return a->value.gid == b->value.gid;
498 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
499 return !strcmp(a->value.user_name, b->value.user_name);
500 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
501 return !strcmp(a->value.group_name, b->value.group_name);
502 default:
503 abort();
504 }
505}
f19f5c96 506
159b042f
JG
507LTTNG_HIDDEN
508void process_attr_value_destroy(struct process_attr_value *value)
509{
510 if (!value) {
511 return;
f19f5c96 512 }
159b042f
JG
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);
f19f5c96 519}
This page took 0.046262 seconds and 4 git commands to generate.