2 * Copyright (C) 2018 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 * SPDX-License-Identifier: GPL-2.0-only
11 #include <sys/types.h>
15 #include <common/defaults.h>
16 #include <common/error.h>
17 #include <common/hashtable/hashtable.h>
18 #include <common/hashtable/utils.h>
19 #include <lttng/lttng-error.h>
20 #include <lttng/tracker-internal.h>
22 #define FALLBACK_USER_BUFLEN 16384
23 #define FALLBACK_GROUP_BUFLEN 16384
25 struct lttng_tracker_list
*lttng_tracker_list_create(void)
27 struct lttng_tracker_list
*t
;
29 t
= zmalloc(sizeof(*t
));
33 t
->ht
= cds_lfht_new(DEFAULT_HT_SIZE
, 1, 0,
34 CDS_LFHT_AUTO_RESIZE
| CDS_LFHT_ACCOUNTING
, NULL
);
38 CDS_INIT_LIST_HEAD(&t
->list_head
);
39 t
->state
= LTTNG_TRACK_ALL
;
47 static int match_tracker_key(struct cds_lfht_node
*node
, const void *key
)
49 const struct lttng_tracker_id
*tracker_key
= key
;
50 struct lttng_tracker_list_node
*tracker_node
;
52 tracker_node
= caa_container_of(
53 node
, struct lttng_tracker_list_node
, ht_node
);
55 return lttng_tracker_id_is_equal(tracker_node
->id
, tracker_key
);
58 static unsigned long hash_tracker_key(
59 const struct lttng_tracker_id
*tracker_key
)
61 unsigned long key_hash
= 0;
64 enum lttng_tracker_id_type type
;
66 /* We do not care for invalid state during hash computation */
67 type
= lttng_tracker_id_get_type(tracker_key
);
68 (void) lttng_tracker_id_get_value(tracker_key
, &value
);
69 (void) lttng_tracker_id_get_string(tracker_key
, &string
);
75 key_hash
^= hash_key_ulong(
76 (void *) (unsigned long) value
, lttng_ht_seed
);
79 key_hash
^= hash_key_str(string
, lttng_ht_seed
);
81 case LTTNG_ID_UNKNOWN
:
84 key_hash
^= hash_key_ulong(
85 (void *) (unsigned long) type
, lttng_ht_seed
);
89 static struct lttng_tracker_id
**lttng_tracker_list_lookup(
90 const struct lttng_tracker_list
*tracker_list
,
91 const struct lttng_tracker_id
*key
)
93 struct lttng_tracker_list_node
*list_node
;
94 struct cds_lfht_iter iter
;
95 struct cds_lfht_node
*node
;
97 cds_lfht_lookup(tracker_list
->ht
, hash_tracker_key(key
),
98 match_tracker_key
, key
, &iter
);
99 node
= cds_lfht_iter_get_node(&iter
);
103 list_node
= caa_container_of(
104 node
, struct lttng_tracker_list_node
, ht_node
);
105 return &list_node
->id
;
108 static void destroy_list_node_rcu(struct rcu_head
*head
)
110 struct lttng_tracker_list_node
*n
= caa_container_of(
111 head
, struct lttng_tracker_list_node
, rcu_head
);
113 lttng_tracker_id_destroy(n
->id
);
117 static void _lttng_tracker_list_remove(struct lttng_tracker_list
*tracker_list
,
118 struct lttng_tracker_list_node
*n
)
120 cds_list_del(&n
->list_node
);
123 cds_lfht_del(tracker_list
->ht
, &n
->ht_node
);
126 call_rcu(&n
->rcu_head
, destroy_list_node_rcu
);
129 static void lttng_tracker_list_reset(struct lttng_tracker_list
*tracker_list
)
131 struct lttng_tracker_list_node
*n
, *t
;
133 cds_list_for_each_entry_safe (
134 n
, t
, &tracker_list
->list_head
, list_node
) {
135 _lttng_tracker_list_remove(tracker_list
, n
);
137 tracker_list
->state
= LTTNG_TRACK_ALL
;
140 /* Protected by session mutex held by caller. */
141 int lttng_tracker_list_add(struct lttng_tracker_list
*tracker_list
,
142 const struct lttng_tracker_id
*_id
)
144 struct lttng_tracker_id
**id
;
145 struct lttng_tracker_list_node
*n
= NULL
;
148 if (lttng_tracker_id_get_type(_id
) == LTTNG_ID_ALL
) {
149 /* Track all, so remove each individual item. */
150 lttng_tracker_list_reset(tracker_list
);
155 id
= lttng_tracker_list_lookup(tracker_list
, _id
);
157 * It is okay to release the RCU read lock here since id is only checked
158 * for != NULL and not dereferenced.
162 ret
= LTTNG_ERR_ID_TRACKED
;
165 n
= zmalloc(sizeof(*n
));
167 ret
= LTTNG_ERR_NOMEM
;
171 n
->id
= lttng_tracker_id_duplicate(_id
);
173 ret
= LTTNG_ERR_NOMEM
;
177 cds_list_add_tail(&n
->list_node
, &tracker_list
->list_head
);
178 tracker_list
->state
= LTTNG_TRACK_LIST
;
181 cds_lfht_add(tracker_list
->ht
, hash_tracker_key(n
->id
), &n
->ht_node
);
193 * Protected by session mutex held by caller.
195 int lttng_tracker_list_remove(struct lttng_tracker_list
*tracker_list
,
196 const struct lttng_tracker_id
*_id
)
198 enum lttng_error_code ret
= LTTNG_OK
;
199 struct lttng_tracker_id
**id
;
200 struct lttng_tracker_list_node
*n
;
202 if (lttng_tracker_id_get_type(_id
) == LTTNG_ID_ALL
) {
204 lttng_tracker_list_reset(tracker_list
);
205 /* Set state to "track none". */
206 tracker_list
->state
= LTTNG_TRACK_NONE
;
211 id
= lttng_tracker_list_lookup(tracker_list
, _id
);
213 ret
= LTTNG_ERR_ID_NOT_TRACKED
;
217 n
= caa_container_of(id
, struct lttng_tracker_list_node
, id
);
218 _lttng_tracker_list_remove(tracker_list
, n
);
226 void lttng_tracker_list_destroy(struct lttng_tracker_list
*tracker_list
)
233 lttng_tracker_list_reset(tracker_list
);
234 ret
= cds_lfht_destroy(tracker_list
->ht
, NULL
);
239 static int lttng_lookup_user(const char *username
, int *result
)
241 struct passwd p
, *pres
;
242 int ret
, retval
= LTTNG_OK
;
246 buflen
= sysconf(_SC_GETPW_R_SIZE_MAX
);
248 buflen
= FALLBACK_USER_BUFLEN
;
250 buf
= zmalloc(buflen
);
252 retval
= LTTNG_ERR_NOMEM
;
256 ret
= getpwnam_r(username
, &p
, buf
, buflen
, &pres
);
263 buf
= zmalloc(buflen
);
265 retval
= LTTNG_ERR_NOMEM
;
278 retval
= LTTNG_ERR_USER_NOT_FOUND
;
280 *result
= (int) p
.pw_uid
;
281 DBG("Lookup of tracker UID/VUID: name '%s' maps to id %d.",
290 retval
= LTTNG_ERR_USER_NOT_FOUND
;
293 retval
= LTTNG_ERR_NOMEM
;
300 static int lttng_lookup_group(const char *groupname
, int *result
)
302 struct group g
, *gres
;
303 int ret
, retval
= LTTNG_OK
;
307 buflen
= sysconf(_SC_GETGR_R_SIZE_MAX
);
309 buflen
= FALLBACK_GROUP_BUFLEN
;
311 buf
= zmalloc(buflen
);
313 retval
= LTTNG_ERR_NOMEM
;
317 ret
= getgrnam_r(groupname
, &g
, buf
, buflen
, &gres
);
324 buf
= zmalloc(buflen
);
326 retval
= LTTNG_ERR_NOMEM
;
339 retval
= LTTNG_ERR_GROUP_NOT_FOUND
;
341 *result
= (int) g
.gr_gid
;
342 DBG("Lookup of tracker GID/GUID: name '%s' maps to id %d.",
351 retval
= LTTNG_ERR_GROUP_NOT_FOUND
;
354 retval
= LTTNG_ERR_NOMEM
;
361 int lttng_tracker_id_lookup_string(enum lttng_tracker_type tracker_type
,
362 const struct lttng_tracker_id
*id
,
365 enum lttng_tracker_id_status status
;
369 switch (lttng_tracker_id_get_type(id
)) {
374 status
= lttng_tracker_id_get_value(id
, &value
);
375 if (status
!= LTTNG_TRACKER_ID_STATUS_OK
) {
376 return LTTNG_ERR_INVALID
;
380 case LTTNG_ID_STRING
:
381 status
= lttng_tracker_id_get_string(id
, &string
);
382 if (status
!= LTTNG_TRACKER_ID_STATUS_OK
) {
383 return LTTNG_ERR_INVALID
;
385 switch (tracker_type
) {
386 case LTTNG_TRACKER_PID
:
387 case LTTNG_TRACKER_VPID
:
388 ERR("Lookup of tracker PID/VPID by name unsupported.");
389 return LTTNG_ERR_INVALID
;
390 case LTTNG_TRACKER_UID
:
391 case LTTNG_TRACKER_VUID
:
392 DBG("Lookup of tracker UID/VUID by name.");
393 return lttng_lookup_user(string
, result
);
394 case LTTNG_TRACKER_GID
:
395 case LTTNG_TRACKER_VGID
:
396 DBG("Lookup of tracker GID/VGID by name.");
397 return lttng_lookup_group(string
, result
);
399 return LTTNG_ERR_INVALID
;
403 return LTTNG_ERR_INVALID
;
408 * Protected by session mutex held by caller.
409 * On success, _ids and the ids it contains must be freed by the caller.
411 int lttng_tracker_id_get_list(const struct lttng_tracker_list
*tracker_list
,
412 struct lttng_tracker_ids
**_ids
)
414 int retval
= LTTNG_OK
, ret
;
415 struct lttng_tracker_list_node
*n
;
416 ssize_t count
= 0, i
= 0;
417 struct lttng_tracker_ids
*ids
= NULL
;
418 struct lttng_tracker_id
*id
;
419 enum lttng_tracker_id_status status
;
421 switch (tracker_list
->state
) {
422 case LTTNG_TRACK_LIST
:
423 cds_list_for_each_entry (
424 n
, &tracker_list
->list_head
, list_node
) {
427 ids
= lttng_tracker_ids_create(count
);
429 PERROR("Failed to allocate tracked ID list");
430 retval
= -LTTNG_ERR_NOMEM
;
433 cds_list_for_each_entry (
434 n
, &tracker_list
->list_head
, list_node
) {
435 id
= lttng_tracker_ids_get_pointer_of_index(ids
, i
);
437 retval
= -LTTNG_ERR_INVALID
;
441 ret
= lttng_tracker_id_copy(id
, n
->id
);
443 retval
= -LTTNG_ERR_NOMEM
;
449 case LTTNG_TRACK_ALL
:
451 ids
= lttng_tracker_ids_create(1);
453 PERROR("Failed to allocate tracked ID list");
454 retval
= -LTTNG_ERR_NOMEM
;
458 id
= lttng_tracker_ids_get_pointer_of_index(ids
, 0);
459 status
= lttng_tracker_id_set_all(id
);
460 if (status
!= LTTNG_TRACKER_ID_STATUS_OK
) {
461 ERR("Invalid tracker id for track all");
462 retval
= -LTTNG_ERR_INVALID
;
466 case LTTNG_TRACK_NONE
:
467 /* No ids track, so we return 0 element collection. */
468 ids
= lttng_tracker_ids_create(0);
470 PERROR("alloc list ids");
471 retval
= -LTTNG_ERR_NOMEM
;
482 lttng_tracker_ids_destroy(ids
);
486 int lttng_tracker_id_set_list(struct lttng_tracker_list
*tracker_list
,
487 const struct lttng_tracker_ids
*ids
)
489 unsigned int i
, count
;
490 const struct lttng_tracker_id
*id
;
491 enum lttng_tracker_id_status status
;
493 assert(tracker_list
);
496 lttng_tracker_list_reset(tracker_list
);
498 status
= lttng_tracker_ids_get_count(ids
, &count
);
499 if (status
!= LTTNG_TRACKER_ID_STATUS_OK
) {
500 return LTTNG_ERR_INVALID
;
504 /* Set state to "track none". */
505 tracker_list
->state
= LTTNG_TRACK_NONE
;
510 id
= lttng_tracker_ids_get_at_index(ids
, 0);
511 if (lttng_tracker_id_get_type(id
) == LTTNG_ID_ALL
) {
517 for (i
= 0; i
< count
; i
++) {
519 id
= lttng_tracker_ids_get_at_index(ids
, i
);
520 ret
= lttng_tracker_list_add(tracker_list
, id
);
521 if (ret
!= LTTNG_OK
) {