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 <lttng/domain.h>
10 #include <lttng/lttng-error.h>
11 #include <lttng/tracker.h>
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>
21 #include <type_traits>
24 struct process_attr_tracker_values_comm_header
{
28 struct process_attr_tracker_value_comm
{
29 /* enum lttng_process_attr_value_type */
32 struct process_attr_integral_value_comm integral
;
33 /* Includes the '\0' terminator. */
39 #define GET_INTEGRAL_COMM_VALUE(value_ptr, as_type) \
40 ((as_type)(std::is_signed<as_type>::value ? (value_ptr)->u._signed : \
41 (value_ptr)->u._unsigned))
43 #define SET_INTEGRAL_COMM_VALUE(comm_value, val) \
44 if (std::is_signed<typeof(val)>::value) { \
45 (comm_value)->u._signed = \
46 (typeof((comm_value)->u._signed)) val; \
48 (comm_value)->u._unsigned = \
49 (typeof((comm_value)->u._unsigned)) val; \
52 static inline bool is_virtual_process_attr(enum lttng_process_attr process_attr
)
54 return process_attr
== LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID
||
55 process_attr
== LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID
||
56 process_attr
== LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID
;
59 static inline bool is_value_type_name(
60 enum lttng_process_attr_value_type value_type
)
62 return value_type
== LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME
||
63 value_type
== LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME
;
66 enum lttng_error_code
process_attr_value_from_comm(
67 enum lttng_domain_type domain
,
68 enum lttng_process_attr process_attr
,
69 enum lttng_process_attr_value_type value_type
,
70 const struct process_attr_integral_value_comm
*integral_value
,
71 const struct lttng_buffer_view
*value_view
,
72 struct process_attr_value
**_value
)
75 enum lttng_error_code ret
= LTTNG_OK
;
76 struct process_attr_value
*value
= zmalloc
<process_attr_value
>();
79 ret
= LTTNG_ERR_NOMEM
;
83 if (value_view
&& value_view
->size
> 0) {
84 if (value_view
->data
[value_view
->size
- 1] != '\0') {
85 ret
= LTTNG_ERR_INVALID
;
88 name
= strdup(value_view
->data
);
90 ret
= LTTNG_ERR_NOMEM
;
95 if (domain
!= LTTNG_DOMAIN_UST
&& domain
!= LTTNG_DOMAIN_KERNEL
) {
96 ERR("Only the user space and kernel space domains may be specified to configure process attribute trackers");
97 ret
= LTTNG_ERR_UNSUPPORTED_DOMAIN
;
101 if (!is_virtual_process_attr(process_attr
) &&
102 domain
!= LTTNG_DOMAIN_KERNEL
) {
103 ERR("Non-virtual process attributes can only be used in the kernel domain");
104 ret
= LTTNG_ERR_UNSUPPORTED_DOMAIN
;
108 /* Only expect a payload for name value types. */
109 if (is_value_type_name(value_type
) &&
110 (!value_view
|| value_view
->size
== 0)) {
111 ret
= LTTNG_ERR_INVALID_PROTOCOL
;
113 } else if (!is_value_type_name(value_type
) && value_view
&&
114 value_view
->size
!= 0) {
115 ret
= LTTNG_ERR_INVALID_PROTOCOL
;
119 value
->type
= value_type
;
120 switch (process_attr
) {
121 case LTTNG_PROCESS_ATTR_PROCESS_ID
:
122 case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID
:
123 if (value_type
!= LTTNG_PROCESS_ATTR_VALUE_TYPE_PID
) {
124 ERR("Invalid value type used for process ID process attribute");
125 ret
= LTTNG_ERR_INVALID
;
129 GET_INTEGRAL_COMM_VALUE(integral_value
, pid_t
);
131 case LTTNG_PROCESS_ATTR_USER_ID
:
132 case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID
:
133 switch (value_type
) {
134 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID
:
135 value
->value
.uid
= GET_INTEGRAL_COMM_VALUE(
136 integral_value
, uid_t
);
138 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME
:
140 ret
= LTTNG_ERR_INVALID
;
144 value
->value
.user_name
= name
;
148 ERR("Invalid value type used for user ID process attribute");
149 ret
= LTTNG_ERR_INVALID
;
153 case LTTNG_PROCESS_ATTR_GROUP_ID
:
154 case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID
:
155 switch (value_type
) {
156 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID
:
157 value
->value
.gid
= GET_INTEGRAL_COMM_VALUE(
158 integral_value
, gid_t
);
160 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME
:
162 ret
= LTTNG_ERR_INVALID
;
166 value
->value
.group_name
= name
;
170 ERR("Invalid value type used for group ID process attribute");
171 ret
= LTTNG_ERR_INVALID
;
176 ret
= LTTNG_ERR_INVALID_PROTOCOL
;
186 process_attr_value_destroy(value
);
190 const char *lttng_process_attr_to_string(enum lttng_process_attr process_attr
)
192 switch (process_attr
) {
193 case LTTNG_PROCESS_ATTR_PROCESS_ID
:
195 case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID
:
196 return "virtual process ID";
197 case LTTNG_PROCESS_ATTR_USER_ID
:
199 case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID
:
200 return "virtual user ID";
201 case LTTNG_PROCESS_ATTR_GROUP_ID
:
203 case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID
:
204 return "virtual group ID";
206 return "unknown process attribute";
210 static void process_attr_tracker_value_destructor(void *ptr
)
212 struct process_attr_value
*value
= (typeof(value
)) ptr
;
214 process_attr_value_destroy(value
);
217 struct lttng_process_attr_values
*lttng_process_attr_values_create(void)
219 struct lttng_process_attr_values
*values
= zmalloc
<lttng_process_attr_values
>();
225 lttng_dynamic_pointer_array_init(
226 &values
->array
, process_attr_tracker_value_destructor
);
231 unsigned int _lttng_process_attr_values_get_count(
232 const struct lttng_process_attr_values
*values
)
234 return (unsigned int) lttng_dynamic_pointer_array_get_count(
238 const struct process_attr_value
*lttng_process_attr_tracker_values_get_at_index(
239 const struct lttng_process_attr_values
*values
,
242 return (process_attr_value
*) lttng_dynamic_pointer_array_get_pointer(&values
->array
, index
);
246 int process_attr_tracker_value_serialize(const struct process_attr_value
*value
,
247 struct lttng_dynamic_buffer
*buffer
)
250 struct process_attr_tracker_value_comm value_comm
= {
251 .type
= (int32_t) value
->type
,
254 const char *name
= NULL
;
256 switch (value
->type
) {
257 case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID
:
258 SET_INTEGRAL_COMM_VALUE(
259 &value_comm
.value
.integral
, value
->value
.pid
);
261 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID
:
262 SET_INTEGRAL_COMM_VALUE(
263 &value_comm
.value
.integral
, value
->value
.uid
);
265 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID
:
266 SET_INTEGRAL_COMM_VALUE(
267 &value_comm
.value
.integral
, value
->value
.gid
);
269 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME
:
270 name
= value
->value
.user_name
;
272 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME
:
273 name
= value
->value
.group_name
;
280 value_comm
.value
.name_len
= strlen(name
) + 1;
283 ret
= lttng_dynamic_buffer_append(
284 buffer
, &value_comm
, sizeof(value_comm
));
290 ret
= lttng_dynamic_buffer_append(
291 buffer
, name
, value_comm
.value
.name_len
);
297 int lttng_process_attr_values_serialize(
298 const struct lttng_process_attr_values
*values
,
299 struct lttng_dynamic_buffer
*buffer
)
302 unsigned int count
, i
;
303 struct process_attr_tracker_values_comm_header header
= {};
305 count
= _lttng_process_attr_values_get_count(values
);
306 header
.count
= (uint32_t) count
;
308 ret
= lttng_dynamic_buffer_append(buffer
, &header
, sizeof(header
));
313 for (i
= 0; i
< count
; i
++) {
314 const struct process_attr_value
*value
=
315 lttng_process_attr_tracker_values_get_at_index(
318 ret
= process_attr_tracker_value_serialize(value
, buffer
);
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
)
335 struct lttng_process_attr_values
*values
;
336 struct lttng_buffer_view header_view
;
337 const struct process_attr_tracker_values_comm_header
*header
;
339 values
= lttng_process_attr_values_create();
344 header_view
= lttng_buffer_view_from_view(
345 buffer_view
, 0, sizeof(*header
));
346 if (!lttng_buffer_view_is_valid(&header_view
)) {
350 offset
= header_view
.size
;
351 header
= (typeof(header
)) header_view
.data
;
354 * Check that the number of values is not absurdly large with respect to
355 * the received buffer's size.
357 if (buffer_view
->size
<
358 header
->count
* sizeof(struct process_attr_tracker_value_comm
)) {
361 for (i
= 0; i
< (unsigned int) header
->count
; i
++) {
363 enum lttng_error_code ret_code
;
364 const struct process_attr_tracker_value_comm
*value_comm
;
365 struct process_attr_value
*value
;
366 enum lttng_process_attr_value_type type
;
367 struct lttng_buffer_view value_view
;
368 struct lttng_buffer_view value_name_view
= {};
370 value_view
= lttng_buffer_view_from_view(
371 buffer_view
, offset
, sizeof(*value_comm
));
372 if (!lttng_buffer_view_is_valid(&value_view
)) {
376 offset
+= value_view
.size
;
377 value_comm
= (typeof(value_comm
)) value_view
.data
;
378 type
= (typeof(type
)) value_comm
->type
;
380 if (is_value_type_name(type
)) {
381 value_name_view
= lttng_buffer_view_from_view(
383 value_comm
->value
.name_len
);
384 if (!lttng_buffer_view_is_valid(&value_name_view
)) {
388 offset
+= value_name_view
.size
;
391 ret_code
= process_attr_value_from_comm(domain
, process_attr
,
392 type
, &value_comm
->value
.integral
,
393 &value_name_view
, &value
);
394 if (ret_code
!= LTTNG_OK
) {
398 ret
= lttng_dynamic_pointer_array_add_pointer(
399 &values
->array
, value
);
401 process_attr_value_destroy(value
);
409 lttng_process_attr_values_destroy(values
);
413 void lttng_process_attr_values_destroy(struct lttng_process_attr_values
*values
)
418 lttng_dynamic_pointer_array_reset(&values
->array
);
422 struct process_attr_value
*process_attr_value_copy(
423 const struct process_attr_value
*value
)
425 struct process_attr_value
*new_value
= NULL
;
431 new_value
= zmalloc
<process_attr_value
>();
435 if (is_value_type_name(value
->type
)) {
437 value
->type
== LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME
?
438 value
->value
.user_name
:
439 value
->value
.group_name
;
440 char **dst
= value
->type
== LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME
?
441 &new_value
->value
.user_name
:
442 &new_value
->value
.group_name
;
444 new_value
->type
= value
->type
;
459 unsigned long process_attr_value_hash(const struct process_attr_value
*a
)
461 unsigned long hash
= hash_key_ulong((void *) a
->type
, lttng_ht_seed
);
464 case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID
:
465 hash
^= hash_key_ulong((void *) (unsigned long) a
->value
.pid
,
468 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID
:
469 hash
^= hash_key_ulong((void *) (unsigned long) a
->value
.uid
,
472 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID
:
473 hash
^= hash_key_ulong((void *) (unsigned long) a
->value
.gid
,
476 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME
:
477 hash
^= hash_key_str(a
->value
.user_name
, lttng_ht_seed
);
479 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME
:
480 hash
^= hash_key_str(a
->value
.group_name
, lttng_ht_seed
);
489 bool process_attr_tracker_value_equal(const struct process_attr_value
*a
,
490 const struct process_attr_value
*b
)
492 if (a
->type
!= b
->type
) {
496 case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID
:
497 return a
->value
.pid
== b
->value
.pid
;
498 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID
:
499 return a
->value
.uid
== b
->value
.uid
;
500 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID
:
501 return a
->value
.gid
== b
->value
.gid
;
502 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME
:
503 return !strcmp(a
->value
.user_name
, b
->value
.user_name
);
504 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME
:
505 return !strcmp(a
->value
.group_name
, b
->value
.group_name
);
511 void process_attr_value_destroy(struct process_attr_value
*value
)
516 if (is_value_type_name(value
->type
)) {
517 free(value
->type
== LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME
?
518 value
->value
.user_name
:
519 value
->value
.group_name
);