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.h>
14 #include <common/error.h>
15 #include <common/hashtable/hashtable.h>
16 #include <common/hashtable/utils.h>
17 #include <common/tracker.h>
21 struct process_attr_tracker_values_comm_header
{
25 struct process_attr_tracker_value_comm
{
26 /* enum lttng_process_attr_value_type */
29 struct process_attr_integral_value_comm integral
;
30 /* Includes the '\0' terminator. */
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))
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; \
44 (comm_value)->u._unsigned = \
45 (typeof((comm_value)->u._unsigned)) value; \
48 static inline bool is_virtual_process_attr(enum lttng_process_attr process_attr
)
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
;
55 static inline bool is_value_type_name(
56 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
;
62 enum lttng_error_code
process_attr_value_from_comm(
63 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(sizeof(*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
) &&
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
;
104 /* Only expect a payload for name value types. */
105 if (is_value_type_name(value_type
) &&
106 (!value_view
|| value_view
->size
== 0)) {
107 ret
= LTTNG_ERR_INVALID_PROTOCOL
;
109 } else if (!is_value_type_name(value_type
) && value_view
&&
110 value_view
->size
!= 0) {
111 ret
= LTTNG_ERR_INVALID_PROTOCOL
;
115 value
->type
= value_type
;
116 switch (process_attr
) {
117 case LTTNG_PROCESS_ATTR_PROCESS_ID
:
118 case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID
:
119 if (value_type
!= LTTNG_PROCESS_ATTR_VALUE_TYPE_PID
) {
120 ERR("Invalid value type used for process ID process attribute");
121 ret
= LTTNG_ERR_INVALID
;
125 GET_INTEGRAL_COMM_VALUE(integral_value
, pid_t
);
127 case LTTNG_PROCESS_ATTR_USER_ID
:
128 case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID
:
129 switch (value_type
) {
130 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID
:
131 value
->value
.uid
= GET_INTEGRAL_COMM_VALUE(
132 integral_value
, uid_t
);
134 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME
:
136 ret
= LTTNG_ERR_INVALID
;
140 value
->value
.user_name
= name
;
144 ERR("Invalid value type used for user ID process attribute");
145 ret
= LTTNG_ERR_INVALID
;
149 case LTTNG_PROCESS_ATTR_GROUP_ID
:
150 case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID
:
151 switch (value_type
) {
152 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID
:
153 value
->value
.gid
= GET_INTEGRAL_COMM_VALUE(
154 integral_value
, gid_t
);
156 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME
:
158 ret
= LTTNG_ERR_INVALID
;
162 value
->value
.group_name
= name
;
166 ERR("Invalid value type used for group ID process attribute");
167 ret
= LTTNG_ERR_INVALID
;
172 ret
= LTTNG_ERR_INVALID_PROTOCOL
;
182 process_attr_value_destroy(value
);
186 const char *lttng_process_attr_to_string(enum lttng_process_attr process_attr
)
188 switch (process_attr
) {
189 case LTTNG_PROCESS_ATTR_PROCESS_ID
:
191 case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID
:
192 return "virtual process ID";
193 case LTTNG_PROCESS_ATTR_USER_ID
:
195 case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID
:
196 return "virtual user ID";
197 case LTTNG_PROCESS_ATTR_GROUP_ID
:
199 case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID
:
200 return "virtual group ID";
202 return "unknown process attribute";
206 static void process_attr_tracker_value_destructor(void *ptr
)
208 struct process_attr_value
*value
= (typeof(value
)) ptr
;
210 process_attr_value_destroy(value
);
213 struct lttng_process_attr_values
*lttng_process_attr_values_create(void)
215 struct lttng_process_attr_values
*values
= zmalloc(sizeof(*values
));
221 lttng_dynamic_pointer_array_init(
222 &values
->array
, process_attr_tracker_value_destructor
);
227 unsigned int _lttng_process_attr_values_get_count(
228 const struct lttng_process_attr_values
*values
)
230 return (unsigned int) lttng_dynamic_pointer_array_get_count(
234 const struct process_attr_value
*lttng_process_attr_tracker_values_get_at_index(
235 const struct lttng_process_attr_values
*values
,
238 return lttng_dynamic_pointer_array_get_pointer(&values
->array
, index
);
242 int process_attr_tracker_value_serialize(const struct process_attr_value
*value
,
243 struct lttng_dynamic_buffer
*buffer
)
246 struct process_attr_tracker_value_comm value_comm
= {
247 .type
= (int32_t) value
->type
,
249 const char *name
= NULL
;
251 switch (value
->type
) {
252 case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID
:
253 SET_INTEGRAL_COMM_VALUE(
254 &value_comm
.value
.integral
, value
->value
.pid
);
256 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID
:
257 SET_INTEGRAL_COMM_VALUE(
258 &value_comm
.value
.integral
, value
->value
.uid
);
260 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID
:
261 SET_INTEGRAL_COMM_VALUE(
262 &value_comm
.value
.integral
, value
->value
.gid
);
264 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME
:
265 name
= value
->value
.user_name
;
267 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME
:
268 name
= value
->value
.group_name
;
275 value_comm
.value
.name_len
= strlen(name
) + 1;
278 ret
= lttng_dynamic_buffer_append(
279 buffer
, &value_comm
, sizeof(value_comm
));
285 ret
= lttng_dynamic_buffer_append(
286 buffer
, name
, value_comm
.value
.name_len
);
292 int lttng_process_attr_values_serialize(
293 const struct lttng_process_attr_values
*values
,
294 struct lttng_dynamic_buffer
*buffer
)
297 unsigned int count
, i
;
298 struct process_attr_tracker_values_comm_header header
= {};
300 count
= _lttng_process_attr_values_get_count(values
);
301 header
.count
= (uint32_t) count
;
303 ret
= lttng_dynamic_buffer_append(buffer
, &header
, sizeof(header
));
308 for (i
= 0; i
< count
; i
++) {
309 const struct process_attr_value
*value
=
310 lttng_process_attr_tracker_values_get_at_index(
313 ret
= process_attr_tracker_value_serialize(value
, buffer
);
322 ssize_t
lttng_process_attr_values_create_from_buffer(
323 enum lttng_domain_type domain
,
324 enum lttng_process_attr process_attr
,
325 const struct lttng_buffer_view
*buffer_view
,
326 struct lttng_process_attr_values
**_values
)
330 struct lttng_process_attr_values
*values
;
331 struct lttng_buffer_view header_view
;
332 const struct process_attr_tracker_values_comm_header
*header
;
334 values
= lttng_process_attr_values_create();
339 header_view
= lttng_buffer_view_from_view(
340 buffer_view
, 0, sizeof(*header
));
341 if (!lttng_buffer_view_is_valid(&header_view
)) {
345 offset
= header_view
.size
;
346 header
= (typeof(header
)) header_view
.data
;
349 * Check that the number of values is not absurdly large with respect to
350 * the received buffer's size.
352 if (buffer_view
->size
<
353 header
->count
* sizeof(struct process_attr_tracker_value_comm
)) {
356 for (i
= 0; i
< (unsigned int) header
->count
; i
++) {
358 enum lttng_error_code ret_code
;
359 const struct process_attr_tracker_value_comm
*value_comm
;
360 struct process_attr_value
*value
;
361 enum lttng_process_attr_value_type type
;
362 struct lttng_buffer_view value_view
;
363 struct lttng_buffer_view value_name_view
= {};
365 value_view
= lttng_buffer_view_from_view(
366 buffer_view
, offset
, sizeof(*value_comm
));
367 if (!lttng_buffer_view_is_valid(&value_view
)) {
371 offset
+= value_view
.size
;
372 value_comm
= (typeof(value_comm
)) value_view
.data
;
373 type
= (typeof(type
)) value_comm
->type
;
375 if (is_value_type_name(type
)) {
376 value_name_view
= lttng_buffer_view_from_view(
378 value_comm
->value
.name_len
);
379 if (!lttng_buffer_view_is_valid(&value_name_view
)) {
383 offset
+= value_name_view
.size
;
386 ret_code
= process_attr_value_from_comm(domain
, process_attr
,
387 type
, &value_comm
->value
.integral
,
388 &value_name_view
, &value
);
389 if (ret_code
!= LTTNG_OK
) {
393 ret
= lttng_dynamic_pointer_array_add_pointer(
394 &values
->array
, value
);
396 process_attr_value_destroy(value
);
404 lttng_process_attr_values_destroy(values
);
408 void lttng_process_attr_values_destroy(struct lttng_process_attr_values
*values
)
413 lttng_dynamic_pointer_array_reset(&values
->array
);
417 struct process_attr_value
*process_attr_value_copy(
418 const struct process_attr_value
*value
)
420 struct process_attr_value
*new_value
= NULL
;
426 new_value
= zmalloc(sizeof(*new_value
));
430 if (is_value_type_name(value
->type
)) {
432 value
->type
== LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME
?
433 value
->value
.user_name
:
434 value
->value
.group_name
;
435 char **dst
= value
->type
== LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME
?
436 &new_value
->value
.user_name
:
437 &new_value
->value
.group_name
;
439 new_value
->type
= value
->type
;
454 unsigned long process_attr_value_hash(const struct process_attr_value
*a
)
456 unsigned long hash
= hash_key_ulong((void *) a
->type
, lttng_ht_seed
);
459 case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID
:
460 hash
^= hash_key_ulong((void *) (unsigned long) a
->value
.pid
,
463 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID
:
464 hash
^= hash_key_ulong((void *) (unsigned long) a
->value
.uid
,
467 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID
:
468 hash
^= hash_key_ulong((void *) (unsigned long) a
->value
.gid
,
471 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME
:
472 hash
^= hash_key_str(a
->value
.user_name
, lttng_ht_seed
);
474 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME
:
475 hash
^= hash_key_str(a
->value
.group_name
, lttng_ht_seed
);
484 bool process_attr_tracker_value_equal(const struct process_attr_value
*a
,
485 const struct process_attr_value
*b
)
487 if (a
->type
!= b
->type
) {
491 case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID
:
492 return a
->value
.pid
== b
->value
.pid
;
493 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID
:
494 return a
->value
.uid
== b
->value
.uid
;
495 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID
:
496 return a
->value
.gid
== b
->value
.gid
;
497 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME
:
498 return !strcmp(a
->value
.user_name
, b
->value
.user_name
);
499 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME
:
500 return !strcmp(a
->value
.group_name
, b
->value
.group_name
);
506 void process_attr_value_destroy(struct process_attr_value
*value
)
511 if (is_value_type_name(value
->type
)) {
512 free(value
->type
== LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME
?
513 value
->value
.user_name
:
514 value
->value
.group_name
);