2 * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
3 * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
5 * SPDX-License-Identifier: LGPL-2.1-only
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>
15 #include <lttng/domain.h>
16 #include <lttng/lttng-error.h>
17 #include <lttng/tracker.h>
20 #include <type_traits>
23 struct process_attr_tracker_values_comm_header
{
27 struct process_attr_tracker_value_comm
{
28 /* enum lttng_process_attr_value_type */
31 struct process_attr_integral_value_comm integral
;
32 /* Includes the '\0' terminator. */
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))
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); \
46 (comm_value)->u._unsigned = (typeof((comm_value)->u._unsigned)) (val); \
49 static inline bool is_virtual_process_attr(enum lttng_process_attr process_attr
)
51 return process_attr
== LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID
||
52 process_attr
== LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID
||
53 process_attr
== LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID
;
56 static inline bool is_value_type_name(enum lttng_process_attr_value_type value_type
)
58 return value_type
== LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME
||
59 value_type
== LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME
;
63 process_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
)
71 enum lttng_error_code ret
= LTTNG_OK
;
72 struct process_attr_value
*value
= zmalloc
<process_attr_value
>();
75 ret
= LTTNG_ERR_NOMEM
;
79 if (value_view
&& value_view
->size
> 0) {
80 if (value_view
->data
[value_view
->size
- 1] != '\0') {
81 ret
= LTTNG_ERR_INVALID
;
84 name
= strdup(value_view
->data
);
86 ret
= LTTNG_ERR_NOMEM
;
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
;
97 if (!is_virtual_process_attr(process_attr
) && domain
!= LTTNG_DOMAIN_KERNEL
) {
98 ERR("Non-virtual process attributes can only be used in the kernel domain");
99 ret
= LTTNG_ERR_UNSUPPORTED_DOMAIN
;
103 /* Only expect a payload for name value types. */
104 if (is_value_type_name(value_type
) && (!value_view
|| value_view
->size
== 0)) {
105 ret
= LTTNG_ERR_INVALID_PROTOCOL
;
107 } else if (!is_value_type_name(value_type
) && value_view
&& value_view
->size
!= 0) {
108 ret
= LTTNG_ERR_INVALID_PROTOCOL
;
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
;
121 value
->value
.pid
= GET_INTEGRAL_COMM_VALUE(integral_value
, pid_t
);
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
:
127 value
->value
.uid
= GET_INTEGRAL_COMM_VALUE(integral_value
, uid_t
);
129 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME
:
131 ret
= LTTNG_ERR_INVALID
;
135 value
->value
.user_name
= name
;
139 ERR("Invalid value type used for user ID process attribute");
140 ret
= LTTNG_ERR_INVALID
;
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
:
148 value
->value
.gid
= GET_INTEGRAL_COMM_VALUE(integral_value
, gid_t
);
150 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME
:
152 ret
= LTTNG_ERR_INVALID
;
156 value
->value
.group_name
= name
;
160 ERR("Invalid value type used for group ID process attribute");
161 ret
= LTTNG_ERR_INVALID
;
166 ret
= LTTNG_ERR_INVALID_PROTOCOL
;
176 process_attr_value_destroy(value
);
180 const char *lttng_process_attr_to_string(enum lttng_process_attr process_attr
)
182 switch (process_attr
) {
183 case LTTNG_PROCESS_ATTR_PROCESS_ID
:
185 case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID
:
186 return "virtual process ID";
187 case LTTNG_PROCESS_ATTR_USER_ID
:
189 case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID
:
190 return "virtual user ID";
191 case LTTNG_PROCESS_ATTR_GROUP_ID
:
193 case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID
:
194 return "virtual group ID";
196 return "unknown process attribute";
200 static void process_attr_tracker_value_destructor(void *ptr
)
202 struct process_attr_value
*value
= (typeof(value
)) ptr
;
204 process_attr_value_destroy(value
);
207 struct lttng_process_attr_values
*lttng_process_attr_values_create()
209 struct lttng_process_attr_values
*values
= zmalloc
<lttng_process_attr_values
>();
215 lttng_dynamic_pointer_array_init(&values
->array
, process_attr_tracker_value_destructor
);
220 unsigned int _lttng_process_attr_values_get_count(const struct lttng_process_attr_values
*values
)
222 return (unsigned int) lttng_dynamic_pointer_array_get_count(&values
->array
);
225 const struct process_attr_value
*
226 lttng_process_attr_tracker_values_get_at_index(const struct lttng_process_attr_values
*values
,
229 return (process_attr_value
*) lttng_dynamic_pointer_array_get_pointer(&values
->array
,
233 static int process_attr_tracker_value_serialize(const struct process_attr_value
*value
,
234 struct lttng_dynamic_buffer
*buffer
)
237 struct process_attr_tracker_value_comm value_comm
= {
238 .type
= (int32_t) value
->type
,
241 const char *name
= nullptr;
243 switch (value
->type
) {
244 case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID
:
245 SET_INTEGRAL_COMM_VALUE(&value_comm
.value
.integral
, value
->value
.pid
);
247 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID
:
248 SET_INTEGRAL_COMM_VALUE(&value_comm
.value
.integral
, value
->value
.uid
);
250 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID
:
251 SET_INTEGRAL_COMM_VALUE(&value_comm
.value
.integral
, value
->value
.gid
);
253 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME
:
254 name
= value
->value
.user_name
;
256 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME
:
257 name
= value
->value
.group_name
;
264 value_comm
.value
.name_len
= strlen(name
) + 1;
267 ret
= lttng_dynamic_buffer_append(buffer
, &value_comm
, sizeof(value_comm
));
273 ret
= lttng_dynamic_buffer_append(buffer
, name
, value_comm
.value
.name_len
);
279 int lttng_process_attr_values_serialize(const struct lttng_process_attr_values
*values
,
280 struct lttng_dynamic_buffer
*buffer
)
283 unsigned int count
, i
;
284 struct process_attr_tracker_values_comm_header header
= {};
286 count
= _lttng_process_attr_values_get_count(values
);
287 header
.count
= (uint32_t) count
;
289 ret
= lttng_dynamic_buffer_append(buffer
, &header
, sizeof(header
));
294 for (i
= 0; i
< count
; i
++) {
295 const struct process_attr_value
*value
=
296 lttng_process_attr_tracker_values_get_at_index(values
, i
);
298 ret
= process_attr_tracker_value_serialize(value
, buffer
);
307 ssize_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
)
314 struct lttng_process_attr_values
*values
;
315 struct lttng_buffer_view header_view
;
316 const struct process_attr_tracker_values_comm_header
*header
;
318 values
= lttng_process_attr_values_create();
323 header_view
= lttng_buffer_view_from_view(buffer_view
, 0, sizeof(*header
));
324 if (!lttng_buffer_view_is_valid(&header_view
)) {
328 offset
= header_view
.size
;
329 header
= (typeof(header
)) header_view
.data
;
332 * Check that the number of values is not absurdly large with respect to
333 * the received buffer's size.
335 if (buffer_view
->size
< header
->count
* sizeof(struct process_attr_tracker_value_comm
)) {
338 for (i
= 0; i
< (unsigned int) header
->count
; i
++) {
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
= {};
347 value_view
= lttng_buffer_view_from_view(buffer_view
, offset
, sizeof(*value_comm
));
348 if (!lttng_buffer_view_is_valid(&value_view
)) {
352 offset
+= value_view
.size
;
353 value_comm
= (typeof(value_comm
)) value_view
.data
;
354 type
= (typeof(type
)) value_comm
->type
;
356 if (is_value_type_name(type
)) {
357 value_name_view
= lttng_buffer_view_from_view(
358 buffer_view
, offset
, value_comm
->value
.name_len
);
359 if (!lttng_buffer_view_is_valid(&value_name_view
)) {
363 offset
+= value_name_view
.size
;
366 ret_code
= process_attr_value_from_comm(domain
,
369 &value_comm
->value
.integral
,
372 if (ret_code
!= LTTNG_OK
) {
376 ret
= lttng_dynamic_pointer_array_add_pointer(&values
->array
, value
);
378 process_attr_value_destroy(value
);
386 lttng_process_attr_values_destroy(values
);
390 void lttng_process_attr_values_destroy(struct lttng_process_attr_values
*values
)
395 lttng_dynamic_pointer_array_reset(&values
->array
);
399 struct process_attr_value
*process_attr_value_copy(const struct process_attr_value
*value
)
401 struct process_attr_value
*new_value
= nullptr;
407 new_value
= zmalloc
<process_attr_value
>();
411 if (is_value_type_name(value
->type
)) {
412 const char *src
= value
->type
== LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME
?
413 value
->value
.user_name
:
414 value
->value
.group_name
;
415 char **dst
= value
->type
== LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME
?
416 &new_value
->value
.user_name
:
417 &new_value
->value
.group_name
;
419 new_value
->type
= value
->type
;
434 unsigned long process_attr_value_hash(const struct process_attr_value
*a
)
436 unsigned long hash
= hash_key_ulong((void *) a
->type
, lttng_ht_seed
);
439 case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID
:
440 hash
^= hash_key_ulong((void *) (unsigned long) a
->value
.pid
, lttng_ht_seed
);
442 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID
:
443 hash
^= hash_key_ulong((void *) (unsigned long) a
->value
.uid
, lttng_ht_seed
);
445 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID
:
446 hash
^= hash_key_ulong((void *) (unsigned long) a
->value
.gid
, lttng_ht_seed
);
448 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME
:
449 hash
^= hash_key_str(a
->value
.user_name
, lttng_ht_seed
);
451 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME
:
452 hash
^= hash_key_str(a
->value
.group_name
, lttng_ht_seed
);
461 bool process_attr_tracker_value_equal(const struct process_attr_value
*a
,
462 const struct process_attr_value
*b
)
464 if (a
->type
!= b
->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
);
483 void process_attr_value_destroy(struct process_attr_value
*value
)
488 if (is_value_type_name(value
->type
)) {
489 free(value
->type
== LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME
?
490 value
->value
.user_name
:
491 value
->value
.group_name
);