0f69c775b75f6d1c08e213fa547bcbbf5feb7daa
[lttng-tools.git] / src / common / tracker.c
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 struct process_attr_tracker_values_comm_header {
22 uint32_t count;
23 };
24
25 struct 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; \
46 }
47
48 static 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;
53 }
54
55 static inline bool is_value_type_name(
56 enum lttng_process_attr_value_type value_type)
57 {
58 return value_type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ||
59 value_type == LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME;
60 }
61
62 LTTNG_HIDDEN
63 enum 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)
70 {
71 char *name = NULL;
72 enum lttng_error_code ret = LTTNG_OK;
73 struct process_attr_value *value = zmalloc(sizeof(*value));
74
75 if (!value) {
76 ret = LTTNG_ERR_NOMEM;
77 goto error;
78 }
79
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 goto error;
89 }
90 }
91
92 if (domain != LTTNG_DOMAIN_UST && domain != LTTNG_DOMAIN_KERNEL) {
93 ERR("Only the user space and kernel space domains may be specified to configure process attribute trackers");
94 ret = LTTNG_ERR_UNSUPPORTED_DOMAIN;
95 goto error;
96 }
97
98 if (!is_virtual_process_attr(process_attr) &&
99 domain != LTTNG_DOMAIN_KERNEL) {
100 ERR("Non-virtual process attributes can only be used in the kernel domain");
101 ret = LTTNG_ERR_UNSUPPORTED_DOMAIN;
102 goto error;
103 }
104
105 /* Only expect a payload for name value types. */
106 if (is_value_type_name(value_type) && value_view->size == 0) {
107 ret = LTTNG_ERR_INVALID_PROTOCOL;
108 goto error;
109 } else if (!is_value_type_name(value_type) && value_view->size != 0) {
110 ret = LTTNG_ERR_INVALID_PROTOCOL;
111 goto error;
112 }
113
114 value->type = value_type;
115 switch (process_attr) {
116 case LTTNG_PROCESS_ATTR_PROCESS_ID:
117 case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
118 if (value_type != LTTNG_PROCESS_ATTR_VALUE_TYPE_PID) {
119 ERR("Invalid value type used for process ID process attribute");
120 ret = LTTNG_ERR_INVALID;
121 goto error;
122 }
123 value->value.pid =
124 GET_INTEGRAL_COMM_VALUE(integral_value, pid_t);
125 break;
126 case LTTNG_PROCESS_ATTR_USER_ID:
127 case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
128 switch (value_type) {
129 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
130 value->value.uid = GET_INTEGRAL_COMM_VALUE(
131 integral_value, uid_t);
132 break;
133 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
134 if (!name) {
135 ret = LTTNG_ERR_INVALID;
136 goto error;
137 }
138
139 value->value.user_name = name;
140 name = NULL;
141 break;
142 default:
143 ERR("Invalid value type used for user ID process attribute");
144 ret = LTTNG_ERR_INVALID;
145 goto error;
146 }
147 break;
148 case LTTNG_PROCESS_ATTR_GROUP_ID:
149 case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
150 switch (value_type) {
151 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
152 value->value.gid = GET_INTEGRAL_COMM_VALUE(
153 integral_value, gid_t);
154 break;
155 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
156 if (!name) {
157 ret = LTTNG_ERR_INVALID;
158 goto error;
159 }
160
161 value->value.group_name = name;
162 name = NULL;
163 break;
164 default:
165 ERR("Invalid value type used for group ID process attribute");
166 ret = LTTNG_ERR_INVALID;
167 goto error;
168 }
169 break;
170 default:
171 ret = LTTNG_ERR_INVALID_PROTOCOL;
172 goto error;
173 }
174
175 *_value = value;
176 value = NULL;
177 free(name);
178 return LTTNG_OK;
179 error:
180 free(name);
181 process_attr_value_destroy(value);
182 return ret;
183 }
184
185 LTTNG_HIDDEN
186 const char *lttng_process_attr_to_string(enum lttng_process_attr process_attr)
187 {
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";
203 }
204 }
205
206 static void process_attr_tracker_value_destructor(void *ptr)
207 {
208 struct process_attr_value *value = (typeof(value)) ptr;
209
210 process_attr_value_destroy(value);
211 }
212
213 LTTNG_HIDDEN
214 struct lttng_process_attr_values *lttng_process_attr_values_create(void)
215 {
216 struct lttng_process_attr_values *values = zmalloc(sizeof(*values));
217
218 if (!values) {
219 goto end;
220 }
221
222 lttng_dynamic_pointer_array_init(
223 &values->array, process_attr_tracker_value_destructor);
224 end:
225 return values;
226 }
227
228 LTTNG_HIDDEN
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 LTTNG_HIDDEN
237 const struct process_attr_value *lttng_process_attr_tracker_values_get_at_index(
238 const struct lttng_process_attr_values *values,
239 unsigned int index)
240 {
241 return lttng_dynamic_pointer_array_get_pointer(&values->array, index);
242 }
243
244 static
245 int process_attr_tracker_value_serialize(const struct process_attr_value *value,
246 struct lttng_dynamic_buffer *buffer)
247 {
248 int ret;
249 struct process_attr_tracker_value_comm value_comm = {
250 .type = (int32_t) value->type,
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);
258 break;
259 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
260 SET_INTEGRAL_COMM_VALUE(
261 &value_comm.value.integral, value->value.uid);
262 break;
263 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
264 SET_INTEGRAL_COMM_VALUE(
265 &value_comm.value.integral, value->value.gid);
266 break;
267 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
268 name = value->value.user_name;
269 break;
270 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
271 name = value->value.group_name;
272 break;
273 default:
274 abort();
275 }
276
277 if (name) {
278 value_comm.value.name_len = strlen(name) + 1;
279 }
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 }
291 end:
292 return ret;
293 }
294
295 LTTNG_HIDDEN
296 int lttng_process_attr_values_serialize(
297 const struct lttng_process_attr_values *values,
298 struct lttng_dynamic_buffer *buffer)
299 {
300 int ret;
301 unsigned int count, i;
302 struct process_attr_tracker_values_comm_header header = {};
303
304 count = _lttng_process_attr_values_get_count(values);
305 header.count = (uint32_t) count;
306
307 ret = lttng_dynamic_buffer_append(buffer, &header, sizeof(header));
308 if (ret) {
309 goto end;
310 }
311
312 for (i = 0; i < count; i++) {
313 const struct process_attr_value *value =
314 lttng_process_attr_tracker_values_get_at_index(
315 values, i);
316
317 ret = process_attr_tracker_value_serialize(value, buffer);
318 if (ret) {
319 goto end;
320 }
321 }
322 end:
323 return ret;
324 }
325
326 LTTNG_HIDDEN
327 ssize_t lttng_process_attr_values_create_from_buffer(
328 enum lttng_domain_type domain,
329 enum lttng_process_attr process_attr,
330 const struct lttng_buffer_view *buffer_view,
331 struct lttng_process_attr_values **_values)
332 {
333 ssize_t offset;
334 unsigned int i;
335 struct lttng_process_attr_values *values;
336 struct lttng_buffer_view header_view;
337 const struct process_attr_tracker_values_comm_header *header;
338
339 values = lttng_process_attr_values_create();
340 if (!values) {
341 goto error;
342 }
343
344 header_view = lttng_buffer_view_from_view(
345 buffer_view, 0, sizeof(*header));
346 if (!header_view.data) {
347 goto error;
348 }
349 offset = header_view.size;
350 header = (typeof(header)) header_view.data;
351
352 /*
353 * Check that the number of values is not absurdly large with respect to
354 * the received buffer's size.
355 */
356 if (buffer_view->size <
357 header->count * sizeof(struct process_attr_tracker_value_comm)) {
358 goto error;
359 }
360 for (i = 0; i < (unsigned int) header->count; i++) {
361 int ret;
362 enum lttng_error_code ret_code;
363 const struct process_attr_tracker_value_comm *value_comm;
364 struct process_attr_value *value;
365 enum lttng_process_attr_value_type type;
366 struct lttng_buffer_view value_view;
367 struct lttng_buffer_view value_name_view = {};
368
369 value_view = lttng_buffer_view_from_view(
370 buffer_view, offset, sizeof(*value_comm));
371 if (!value_view.data) {
372 goto error;
373 }
374
375 offset += value_view.size;
376 value_comm = (typeof(value_comm)) value_view.data;
377 type = (typeof(type)) value_comm->type;
378
379 if (is_value_type_name(type)) {
380 value_name_view = lttng_buffer_view_from_view(
381 buffer_view, offset,
382 value_comm->value.name_len);
383 offset += value_name_view.size;
384 }
385 ret_code = process_attr_value_from_comm(domain, process_attr,
386 type, &value_comm->value.integral,
387 &value_name_view, &value);
388 if (ret_code != LTTNG_OK) {
389 goto error;
390 }
391
392 ret = lttng_dynamic_pointer_array_add_pointer(
393 &values->array, value);
394 if (ret) {
395 process_attr_value_destroy(value);
396 goto error;
397 }
398 }
399
400 *_values = values;
401 return offset;
402 error:
403 lttng_process_attr_values_destroy(values);
404 return -1;
405 }
406
407 LTTNG_HIDDEN
408 void lttng_process_attr_values_destroy(struct lttng_process_attr_values *values)
409 {
410 if (!values) {
411 return;
412 }
413 lttng_dynamic_pointer_array_reset(&values->array);
414 free(values);
415 }
416
417 LTTNG_HIDDEN
418 struct process_attr_value *process_attr_value_copy(
419 const struct process_attr_value *value)
420 {
421 struct process_attr_value *new_value = NULL;
422
423 if (!value) {
424 goto end;
425 }
426
427 new_value = zmalloc(sizeof(*new_value));
428 if (!new_value) {
429 goto end;
430 }
431 if (is_value_type_name(value->type)) {
432 const char *src =
433 value->type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ?
434 value->value.user_name :
435 value->value.group_name;
436 char **dst = value->type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ?
437 &new_value->value.user_name :
438 &new_value->value.group_name;
439
440 new_value->type = value->type;
441 *dst = strdup(src);
442 if (!*dst) {
443 goto error;
444 }
445 } else {
446 *new_value = *value;
447 }
448 end:
449 return new_value;
450 error:
451 free(new_value);
452 return NULL;
453 }
454
455 LTTNG_HIDDEN
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 LTTNG_HIDDEN
487 bool process_attr_tracker_value_equal(const struct process_attr_value *a,
488 const struct process_attr_value *b)
489 {
490 if (a->type != b->type) {
491 return false;
492 }
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 }
508
509 LTTNG_HIDDEN
510 void process_attr_value_destroy(struct process_attr_value *value)
511 {
512 if (!value) {
513 return;
514 }
515 if (is_value_type_name(value->type)) {
516 free(value->type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ?
517 value->value.user_name :
518 value->value.group_name);
519 }
520 free(value);
521 }
This page took 0.061319 seconds and 4 git commands to generate.