2 * Copyright (C) 2018 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2 only,
6 * as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include <sys/types.h>
25 #include <common/defaults.h>
26 #include <common/error.h>
27 #include <common/hashtable/hashtable.h>
28 #include <common/hashtable/utils.h>
29 #include <lttng/lttng-error.h>
30 #include <lttng/tracker-internal.h>
32 #define FALLBACK_USER_BUFLEN 16384
33 #define FALLBACK_GROUP_BUFLEN 16384
35 struct lttng_tracker_list
*lttng_tracker_list_create(void)
37 struct lttng_tracker_list
*t
;
39 t
= zmalloc(sizeof(*t
));
43 t
->ht
= cds_lfht_new(DEFAULT_HT_SIZE
, 1, 0,
44 CDS_LFHT_AUTO_RESIZE
| CDS_LFHT_ACCOUNTING
, NULL
);
48 CDS_INIT_LIST_HEAD(&t
->list_head
);
49 t
->state
= LTTNG_TRACK_ALL
;
57 static int match_tracker_key(struct cds_lfht_node
*node
, const void *key
)
59 const struct lttng_tracker_id
*tracker_key
= key
;
60 struct lttng_tracker_list_node
*tracker_node
;
62 tracker_node
= caa_container_of(
63 node
, struct lttng_tracker_list_node
, ht_node
);
65 return lttng_tracker_id_is_equal(tracker_node
->id
, tracker_key
);
68 static unsigned long hash_tracker_key(
69 const struct lttng_tracker_id
*tracker_key
)
71 unsigned long key_hash
= 0;
74 enum lttng_tracker_id_type type
;
76 /* We do not care for invalid state during hash computation */
77 type
= lttng_tracker_id_get_type(tracker_key
);
78 (void) lttng_tracker_id_get_value(tracker_key
, &value
);
79 (void) lttng_tracker_id_get_string(tracker_key
, &string
);
85 key_hash
^= hash_key_ulong(
86 (void *) (unsigned long) value
, lttng_ht_seed
);
89 key_hash
^= hash_key_str(string
, lttng_ht_seed
);
91 case LTTNG_ID_UNKNOWN
:
94 key_hash
^= hash_key_ulong(
95 (void *) (unsigned long) type
, lttng_ht_seed
);
99 static struct lttng_tracker_id
**lttng_tracker_list_lookup(
100 const struct lttng_tracker_list
*tracker_list
,
101 const struct lttng_tracker_id
*key
)
103 struct lttng_tracker_list_node
*list_node
;
104 struct cds_lfht_iter iter
;
105 struct cds_lfht_node
*node
;
107 cds_lfht_lookup(tracker_list
->ht
, hash_tracker_key(key
),
108 match_tracker_key
, key
, &iter
);
109 node
= cds_lfht_iter_get_node(&iter
);
113 list_node
= caa_container_of(
114 node
, struct lttng_tracker_list_node
, ht_node
);
115 return &list_node
->id
;
118 static void destroy_list_node_rcu(struct rcu_head
*head
)
120 struct lttng_tracker_list_node
*n
= caa_container_of(
121 head
, struct lttng_tracker_list_node
, rcu_head
);
123 lttng_tracker_id_destroy(n
->id
);
127 static void _lttng_tracker_list_remove(struct lttng_tracker_list
*tracker_list
,
128 struct lttng_tracker_list_node
*n
)
130 cds_list_del(&n
->list_node
);
133 cds_lfht_del(tracker_list
->ht
, &n
->ht_node
);
136 call_rcu(&n
->rcu_head
, destroy_list_node_rcu
);
139 static void lttng_tracker_list_reset(struct lttng_tracker_list
*tracker_list
)
141 struct lttng_tracker_list_node
*n
, *t
;
143 cds_list_for_each_entry_safe (
144 n
, t
, &tracker_list
->list_head
, list_node
) {
145 _lttng_tracker_list_remove(tracker_list
, n
);
147 tracker_list
->state
= LTTNG_TRACK_ALL
;
150 /* Protected by session mutex held by caller. */
151 int lttng_tracker_list_add(struct lttng_tracker_list
*tracker_list
,
152 const struct lttng_tracker_id
*_id
)
154 struct lttng_tracker_id
**id
;
155 struct lttng_tracker_list_node
*n
= NULL
;
158 if (lttng_tracker_id_get_type(_id
) == LTTNG_ID_ALL
) {
159 /* Track all, so remove each individual item. */
160 lttng_tracker_list_reset(tracker_list
);
165 id
= lttng_tracker_list_lookup(tracker_list
, _id
);
167 * It is okay to release the RCU read lock here since id is only checked
168 * for != NULL and not dereferenced.
172 ret
= LTTNG_ERR_ID_TRACKED
;
175 n
= zmalloc(sizeof(*n
));
177 ret
= LTTNG_ERR_NOMEM
;
181 n
->id
= lttng_tracker_id_duplicate(_id
);
183 ret
= LTTNG_ERR_NOMEM
;
187 cds_list_add_tail(&n
->list_node
, &tracker_list
->list_head
);
188 tracker_list
->state
= LTTNG_TRACK_LIST
;
191 cds_lfht_add(tracker_list
->ht
, hash_tracker_key(n
->id
), &n
->ht_node
);
203 * Protected by session mutex held by caller.
205 int lttng_tracker_list_remove(struct lttng_tracker_list
*tracker_list
,
206 const struct lttng_tracker_id
*_id
)
208 enum lttng_error_code ret
= LTTNG_OK
;
209 struct lttng_tracker_id
**id
;
210 struct lttng_tracker_list_node
*n
;
212 if (lttng_tracker_id_get_type(_id
) == LTTNG_ID_ALL
) {
214 lttng_tracker_list_reset(tracker_list
);
215 /* Set state to "track none". */
216 tracker_list
->state
= LTTNG_TRACK_NONE
;
221 id
= lttng_tracker_list_lookup(tracker_list
, _id
);
223 ret
= LTTNG_ERR_ID_NOT_TRACKED
;
227 n
= caa_container_of(id
, struct lttng_tracker_list_node
, id
);
228 _lttng_tracker_list_remove(tracker_list
, n
);
236 void lttng_tracker_list_destroy(struct lttng_tracker_list
*tracker_list
)
241 lttng_tracker_list_reset(tracker_list
);
242 cds_lfht_destroy(tracker_list
->ht
, NULL
);
246 static int lttng_lookup_user(const char *username
, int *result
)
248 struct passwd p
, *pres
;
249 int ret
, retval
= LTTNG_OK
;
253 buflen
= sysconf(_SC_GETPW_R_SIZE_MAX
);
255 buflen
= FALLBACK_USER_BUFLEN
;
257 buf
= zmalloc(buflen
);
259 retval
= LTTNG_ERR_NOMEM
;
263 ret
= getpwnam_r(username
, &p
, buf
, buflen
, &pres
);
270 buf
= zmalloc(buflen
);
272 retval
= LTTNG_ERR_NOMEM
;
285 retval
= LTTNG_ERR_USER_NOT_FOUND
;
287 *result
= (int) p
.pw_uid
;
288 DBG("Lookup of tracker UID/VUID: name '%s' maps to id %d.",
297 retval
= LTTNG_ERR_USER_NOT_FOUND
;
300 retval
= LTTNG_ERR_NOMEM
;
307 static int lttng_lookup_group(const char *groupname
, int *result
)
309 struct group g
, *gres
;
310 int ret
, retval
= LTTNG_OK
;
314 buflen
= sysconf(_SC_GETGR_R_SIZE_MAX
);
316 buflen
= FALLBACK_GROUP_BUFLEN
;
318 buf
= zmalloc(buflen
);
320 retval
= LTTNG_ERR_NOMEM
;
324 ret
= getgrnam_r(groupname
, &g
, buf
, buflen
, &gres
);
331 buf
= zmalloc(buflen
);
333 retval
= LTTNG_ERR_NOMEM
;
346 retval
= LTTNG_ERR_GROUP_NOT_FOUND
;
348 *result
= (int) g
.gr_gid
;
349 DBG("Lookup of tracker GID/GUID: name '%s' maps to id %d.",
358 retval
= LTTNG_ERR_GROUP_NOT_FOUND
;
361 retval
= LTTNG_ERR_NOMEM
;
368 int lttng_tracker_id_lookup_string(enum lttng_tracker_type tracker_type
,
369 const struct lttng_tracker_id
*id
,
372 enum lttng_tracker_id_status status
;
376 switch (lttng_tracker_id_get_type(id
)) {
381 status
= lttng_tracker_id_get_value(id
, &value
);
382 if (status
!= LTTNG_TRACKER_ID_STATUS_OK
) {
383 return LTTNG_ERR_INVALID
;
387 case LTTNG_ID_STRING
:
388 status
= lttng_tracker_id_get_string(id
, &string
);
389 if (status
!= LTTNG_TRACKER_ID_STATUS_OK
) {
390 return LTTNG_ERR_INVALID
;
392 switch (tracker_type
) {
393 case LTTNG_TRACKER_PID
:
394 case LTTNG_TRACKER_VPID
:
395 ERR("Lookup of tracker PID/VPID by name unsupported.");
396 return LTTNG_ERR_INVALID
;
397 case LTTNG_TRACKER_UID
:
398 case LTTNG_TRACKER_VUID
:
399 DBG("Lookup of tracker UID/VUID by name.");
400 return lttng_lookup_user(string
, result
);
401 case LTTNG_TRACKER_GID
:
402 case LTTNG_TRACKER_VGID
:
403 DBG("Lookup of tracker GID/VGID by name.");
404 return lttng_lookup_group(string
, result
);
406 return LTTNG_ERR_INVALID
;
410 return LTTNG_ERR_INVALID
;
415 * Protected by session mutex held by caller.
416 * On success, _ids and the ids it contains must be freed by the caller.
418 int lttng_tracker_id_get_list(const struct lttng_tracker_list
*tracker_list
,
419 struct lttng_tracker_ids
**_ids
)
421 int retval
= LTTNG_OK
, ret
;
422 struct lttng_tracker_list_node
*n
;
423 ssize_t count
= 0, i
= 0;
424 struct lttng_tracker_ids
*ids
= NULL
;
425 struct lttng_tracker_id
*id
;
426 enum lttng_tracker_id_status status
;
428 switch (tracker_list
->state
) {
429 case LTTNG_TRACK_LIST
:
430 cds_list_for_each_entry (
431 n
, &tracker_list
->list_head
, list_node
) {
434 ids
= lttng_tracker_ids_create(count
);
436 PERROR("Failed to allocate tracked ID list");
437 retval
= -LTTNG_ERR_NOMEM
;
440 cds_list_for_each_entry (
441 n
, &tracker_list
->list_head
, list_node
) {
442 id
= lttng_tracker_ids_get_pointer_of_index(ids
, i
);
444 retval
= -LTTNG_ERR_INVALID
;
448 ret
= lttng_tracker_id_copy(id
, n
->id
);
450 retval
= -LTTNG_ERR_NOMEM
;
456 case LTTNG_TRACK_ALL
:
458 ids
= lttng_tracker_ids_create(1);
460 PERROR("Failed to allocate tracked ID list");
461 retval
= -LTTNG_ERR_NOMEM
;
465 id
= lttng_tracker_ids_get_pointer_of_index(ids
, 0);
466 status
= lttng_tracker_id_set_all(id
);
467 if (status
!= LTTNG_TRACKER_ID_STATUS_OK
) {
468 ERR("Invalid tracker id for track all");
469 retval
= -LTTNG_ERR_INVALID
;
473 case LTTNG_TRACK_NONE
:
474 /* No ids track, so we return 0 element collection. */
475 ids
= lttng_tracker_ids_create(0);
477 PERROR("alloc list ids");
478 retval
= -LTTNG_ERR_NOMEM
;
489 lttng_tracker_ids_destroy(ids
);
493 int lttng_tracker_id_set_list(struct lttng_tracker_list
*tracker_list
,
494 const struct lttng_tracker_ids
*ids
)
496 unsigned int i
, count
;
497 const struct lttng_tracker_id
*id
;
498 enum lttng_tracker_id_status status
;
500 assert(tracker_list
);
503 lttng_tracker_list_reset(tracker_list
);
505 status
= lttng_tracker_ids_get_count(ids
, &count
);
506 if (status
!= LTTNG_TRACKER_ID_STATUS_OK
) {
507 return LTTNG_ERR_INVALID
;
511 /* Set state to "track none". */
512 tracker_list
->state
= LTTNG_TRACK_NONE
;
517 id
= lttng_tracker_ids_get_at_index(ids
, 0);
518 if (lttng_tracker_id_get_type(id
) == LTTNG_ID_ALL
) {
524 for (i
= 0; i
< count
; i
++) {
526 id
= lttng_tracker_ids_get_at_index(ids
, i
);
527 ret
= lttng_tracker_list_add(tracker_list
, id
);
528 if (ret
!= LTTNG_OK
) {