Fix: unchecked return value of cds_lfht_destroy()
[lttng-tools.git] / src / bin / lttng-sessiond / tracker.c
CommitLineData
a8c3ad3e 1/*
ab5be9fa 2 * Copyright (C) 2018 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
a8c3ad3e 3 *
ab5be9fa 4 * SPDX-License-Identifier: GPL-2.0-only
a8c3ad3e 5 *
a8c3ad3e
MD
6 */
7
8#define _LGPL_SOURCE
9#include <grp.h>
10#include <pwd.h>
11#include <sys/types.h>
12#include <unistd.h>
13
14#include "tracker.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>
2d97a006 20#include <lttng/tracker-internal.h>
a8c3ad3e
MD
21
22#define FALLBACK_USER_BUFLEN 16384
23#define FALLBACK_GROUP_BUFLEN 16384
24
25struct lttng_tracker_list *lttng_tracker_list_create(void)
26{
27 struct lttng_tracker_list *t;
28
29 t = zmalloc(sizeof(*t));
30 if (!t) {
31 return NULL;
32 }
33 t->ht = cds_lfht_new(DEFAULT_HT_SIZE, 1, 0,
34 CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING, NULL);
35 if (!t->ht) {
36 goto error;
37 }
38 CDS_INIT_LIST_HEAD(&t->list_head);
39 t->state = LTTNG_TRACK_ALL;
40 return t;
41
42error:
43 free(t);
44 return NULL;
45}
46
47static int match_tracker_key(struct cds_lfht_node *node, const void *key)
48{
49 const struct lttng_tracker_id *tracker_key = key;
50 struct lttng_tracker_list_node *tracker_node;
51
52 tracker_node = caa_container_of(
53 node, struct lttng_tracker_list_node, ht_node);
2d97a006
JR
54
55 return lttng_tracker_id_is_equal(tracker_node->id, tracker_key);
a8c3ad3e
MD
56}
57
58static unsigned long hash_tracker_key(
59 const struct lttng_tracker_id *tracker_key)
60{
61 unsigned long key_hash = 0;
2d97a006
JR
62 int value;
63 const char *string;
64 enum lttng_tracker_id_type type;
65
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);
a8c3ad3e 70
2d97a006 71 switch (type) {
a8c3ad3e
MD
72 case LTTNG_ID_ALL:
73 break;
74 case LTTNG_ID_VALUE:
75 key_hash ^= hash_key_ulong(
2d97a006 76 (void *) (unsigned long) value, lttng_ht_seed);
a8c3ad3e
MD
77 break;
78 case LTTNG_ID_STRING:
2d97a006 79 key_hash ^= hash_key_str(string, lttng_ht_seed);
a8c3ad3e
MD
80 break;
81 case LTTNG_ID_UNKNOWN:
82 break;
83 }
2d97a006
JR
84 key_hash ^= hash_key_ulong(
85 (void *) (unsigned long) type, lttng_ht_seed);
a8c3ad3e
MD
86 return key_hash;
87}
88
2d97a006 89static struct lttng_tracker_id **lttng_tracker_list_lookup(
a8c3ad3e
MD
90 const struct lttng_tracker_list *tracker_list,
91 const struct lttng_tracker_id *key)
92{
93 struct lttng_tracker_list_node *list_node;
94 struct cds_lfht_iter iter;
95 struct cds_lfht_node *node;
96
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);
100 if (!node) {
101 return NULL;
102 }
103 list_node = caa_container_of(
104 node, struct lttng_tracker_list_node, ht_node);
105 return &list_node->id;
106}
107
108static void destroy_list_node_rcu(struct rcu_head *head)
109{
110 struct lttng_tracker_list_node *n = caa_container_of(
111 head, struct lttng_tracker_list_node, rcu_head);
112
2d97a006 113 lttng_tracker_id_destroy(n->id);
a8c3ad3e
MD
114 free(n);
115}
116
117static void _lttng_tracker_list_remove(struct lttng_tracker_list *tracker_list,
118 struct lttng_tracker_list_node *n)
119{
120 cds_list_del(&n->list_node);
121
122 rcu_read_lock();
123 cds_lfht_del(tracker_list->ht, &n->ht_node);
124 rcu_read_unlock();
125
126 call_rcu(&n->rcu_head, destroy_list_node_rcu);
127}
128
129static void lttng_tracker_list_reset(struct lttng_tracker_list *tracker_list)
130{
131 struct lttng_tracker_list_node *n, *t;
132
133 cds_list_for_each_entry_safe (
134 n, t, &tracker_list->list_head, list_node) {
135 _lttng_tracker_list_remove(tracker_list, n);
136 }
137 tracker_list->state = LTTNG_TRACK_ALL;
138}
139
140/* Protected by session mutex held by caller. */
141int lttng_tracker_list_add(struct lttng_tracker_list *tracker_list,
142 const struct lttng_tracker_id *_id)
143{
2d97a006
JR
144 struct lttng_tracker_id **id;
145 struct lttng_tracker_list_node *n = NULL;
a8c3ad3e
MD
146 int ret;
147
2d97a006 148 if (lttng_tracker_id_get_type(_id) == LTTNG_ID_ALL) {
a8c3ad3e
MD
149 /* Track all, so remove each individual item. */
150 lttng_tracker_list_reset(tracker_list);
2d97a006
JR
151 ret = LTTNG_OK;
152 goto error;
a8c3ad3e
MD
153 }
154 rcu_read_lock();
155 id = lttng_tracker_list_lookup(tracker_list, _id);
156 /*
157 * It is okay to release the RCU read lock here since id is only checked
158 * for != NULL and not dereferenced.
159 */
160 rcu_read_unlock();
161 if (id) {
2d97a006
JR
162 ret = LTTNG_ERR_ID_TRACKED;
163 goto error;
a8c3ad3e
MD
164 }
165 n = zmalloc(sizeof(*n));
166 if (!n) {
2d97a006
JR
167 ret = LTTNG_ERR_NOMEM;
168 goto error;
a8c3ad3e 169 }
2d97a006 170
a7a533cd 171 n->id = lttng_tracker_id_duplicate(_id);
2d97a006
JR
172 if (!n->id) {
173 ret = LTTNG_ERR_NOMEM;
174 goto error;
a8c3ad3e
MD
175 }
176
177 cds_list_add_tail(&n->list_node, &tracker_list->list_head);
178 tracker_list->state = LTTNG_TRACK_LIST;
179
180 rcu_read_lock();
2d97a006 181 cds_lfht_add(tracker_list->ht, hash_tracker_key(n->id), &n->ht_node);
a8c3ad3e
MD
182 rcu_read_unlock();
183
184 return LTTNG_OK;
185
186error:
187 free(n);
188 return ret;
189}
190
191/*
192 * Lookup and remove.
193 * Protected by session mutex held by caller.
194 */
195int lttng_tracker_list_remove(struct lttng_tracker_list *tracker_list,
196 const struct lttng_tracker_id *_id)
197{
198 enum lttng_error_code ret = LTTNG_OK;
2d97a006 199 struct lttng_tracker_id **id;
a8c3ad3e
MD
200 struct lttng_tracker_list_node *n;
201
2d97a006 202 if (lttng_tracker_id_get_type(_id) == LTTNG_ID_ALL) {
a8c3ad3e
MD
203 /* Untrack all. */
204 lttng_tracker_list_reset(tracker_list);
205 /* Set state to "track none". */
206 tracker_list->state = LTTNG_TRACK_NONE;
207 goto end;
208 }
209
210 rcu_read_lock();
211 id = lttng_tracker_list_lookup(tracker_list, _id);
212 if (!id) {
213 ret = LTTNG_ERR_ID_NOT_TRACKED;
214 goto rcu_unlock;
215 }
216
217 n = caa_container_of(id, struct lttng_tracker_list_node, id);
218 _lttng_tracker_list_remove(tracker_list, n);
219
220rcu_unlock:
221 rcu_read_unlock();
222end:
223 return ret;
224}
225
226void lttng_tracker_list_destroy(struct lttng_tracker_list *tracker_list)
227{
b7e1aba3
JG
228 int ret;
229
a8c3ad3e
MD
230 if (!tracker_list) {
231 return;
232 }
233 lttng_tracker_list_reset(tracker_list);
b7e1aba3
JG
234 ret = cds_lfht_destroy(tracker_list->ht, NULL);
235 assert(!ret);
a8c3ad3e
MD
236 free(tracker_list);
237}
238
239static int lttng_lookup_user(const char *username, int *result)
240{
241 struct passwd p, *pres;
242 int ret, retval = LTTNG_OK;
243 char *buf = NULL;
244 ssize_t buflen;
245
246 buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
247 if (buflen < 0) {
248 buflen = FALLBACK_USER_BUFLEN;
249 }
250 buf = zmalloc(buflen);
251 if (!buf) {
252 retval = LTTNG_ERR_NOMEM;
253 goto end;
254 }
255 for (;;) {
256 ret = getpwnam_r(username, &p, buf, buflen, &pres);
257 switch (ret) {
258 case EINTR:
259 continue;
260 case ERANGE:
261 buflen *= 2;
262 free(buf);
263 buf = zmalloc(buflen);
264 if (!buf) {
265 retval = LTTNG_ERR_NOMEM;
266 goto end;
267 }
268 continue;
269 default:
270 goto end_loop;
271 }
272 }
273end_loop:
274
275 switch (ret) {
276 case 0:
277 if (pres == NULL) {
278 retval = LTTNG_ERR_USER_NOT_FOUND;
279 } else {
280 *result = (int) p.pw_uid;
281 DBG("Lookup of tracker UID/VUID: name '%s' maps to id %d.",
282 username, *result);
283 retval = LTTNG_OK;
284 }
285 break;
286 case ENOENT:
287 case ESRCH:
288 case EBADF:
289 case EPERM:
290 retval = LTTNG_ERR_USER_NOT_FOUND;
291 break;
292 default:
293 retval = LTTNG_ERR_NOMEM;
294 }
295end:
296 free(buf);
297 return retval;
298}
299
300static int lttng_lookup_group(const char *groupname, int *result)
301{
302 struct group g, *gres;
303 int ret, retval = LTTNG_OK;
304 char *buf = NULL;
305 ssize_t buflen;
306
307 buflen = sysconf(_SC_GETGR_R_SIZE_MAX);
308 if (buflen < 0) {
309 buflen = FALLBACK_GROUP_BUFLEN;
310 }
311 buf = zmalloc(buflen);
312 if (!buf) {
313 retval = LTTNG_ERR_NOMEM;
314 goto end;
315 }
316 for (;;) {
317 ret = getgrnam_r(groupname, &g, buf, buflen, &gres);
318 switch (ret) {
319 case EINTR:
320 continue;
321 case ERANGE:
322 buflen *= 2;
323 free(buf);
324 buf = zmalloc(buflen);
325 if (!buf) {
326 retval = LTTNG_ERR_NOMEM;
327 goto end;
328 }
329 continue;
330 default:
331 goto end_loop;
332 }
333 }
334end_loop:
335
336 switch (ret) {
337 case 0:
338 if (gres == NULL) {
339 retval = LTTNG_ERR_GROUP_NOT_FOUND;
340 } else {
341 *result = (int) g.gr_gid;
342 DBG("Lookup of tracker GID/GUID: name '%s' maps to id %d.",
343 groupname, *result);
344 retval = LTTNG_OK;
345 }
346 break;
347 case ENOENT:
348 case ESRCH:
349 case EBADF:
350 case EPERM:
351 retval = LTTNG_ERR_GROUP_NOT_FOUND;
352 break;
353 default:
354 retval = LTTNG_ERR_NOMEM;
355 }
356end:
357 free(buf);
358 return retval;
359}
360
361int lttng_tracker_id_lookup_string(enum lttng_tracker_type tracker_type,
362 const struct lttng_tracker_id *id,
363 int *result)
364{
2d97a006
JR
365 enum lttng_tracker_id_status status;
366 int value;
367 const char *string;
368
369 switch (lttng_tracker_id_get_type(id)) {
a8c3ad3e
MD
370 case LTTNG_ID_ALL:
371 *result = -1;
372 return LTTNG_OK;
373 case LTTNG_ID_VALUE:
2d97a006
JR
374 status = lttng_tracker_id_get_value(id, &value);
375 if (status != LTTNG_TRACKER_ID_STATUS_OK) {
376 return LTTNG_ERR_INVALID;
377 }
a8c3ad3e
MD
378 *result = id->value;
379 return LTTNG_OK;
380 case LTTNG_ID_STRING:
2d97a006
JR
381 status = lttng_tracker_id_get_string(id, &string);
382 if (status != LTTNG_TRACKER_ID_STATUS_OK) {
383 return LTTNG_ERR_INVALID;
384 }
a8c3ad3e
MD
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.");
2d97a006 393 return lttng_lookup_user(string, result);
a8c3ad3e
MD
394 case LTTNG_TRACKER_GID:
395 case LTTNG_TRACKER_VGID:
396 DBG("Lookup of tracker GID/VGID by name.");
2d97a006 397 return lttng_lookup_group(string, result);
a8c3ad3e
MD
398 default:
399 return LTTNG_ERR_INVALID;
400 }
401 break;
402 default:
403 return LTTNG_ERR_INVALID;
404 }
405}
406
407/*
408 * Protected by session mutex held by caller.
2d97a006 409 * On success, _ids and the ids it contains must be freed by the caller.
a8c3ad3e 410 */
a7a533cd
JR
411int lttng_tracker_id_get_list(const struct lttng_tracker_list *tracker_list,
412 struct lttng_tracker_ids **_ids)
a8c3ad3e 413{
a7a533cd 414 int retval = LTTNG_OK, ret;
a8c3ad3e 415 struct lttng_tracker_list_node *n;
a7a533cd
JR
416 ssize_t count = 0, i = 0;
417 struct lttng_tracker_ids *ids = NULL;
418 struct lttng_tracker_id *id;
2d97a006 419 enum lttng_tracker_id_status status;
a8c3ad3e
MD
420
421 switch (tracker_list->state) {
422 case LTTNG_TRACK_LIST:
423 cds_list_for_each_entry (
424 n, &tracker_list->list_head, list_node) {
425 count++;
426 }
a7a533cd 427 ids = lttng_tracker_ids_create(count);
a8c3ad3e
MD
428 if (ids == NULL) {
429 PERROR("Failed to allocate tracked ID list");
430 retval = -LTTNG_ERR_NOMEM;
431 goto end;
432 }
433 cds_list_for_each_entry (
434 n, &tracker_list->list_head, list_node) {
a7a533cd
JR
435 id = lttng_tracker_ids_get_pointer_of_index(ids, i);
436 if (!id) {
437 retval = -LTTNG_ERR_INVALID;
438 goto error;
439 }
440
441 ret = lttng_tracker_id_copy(id, n->id);
442 if (ret) {
2d97a006
JR
443 retval = -LTTNG_ERR_NOMEM;
444 goto error;
a8c3ad3e
MD
445 }
446 i++;
447 }
a8c3ad3e
MD
448 break;
449 case LTTNG_TRACK_ALL:
a7a533cd
JR
450
451 ids = lttng_tracker_ids_create(1);
a8c3ad3e
MD
452 if (ids == NULL) {
453 PERROR("Failed to allocate tracked ID list");
454 retval = -LTTNG_ERR_NOMEM;
455 goto end;
456 }
a7a533cd
JR
457
458 id = lttng_tracker_ids_get_pointer_of_index(ids, 0);
459 status = lttng_tracker_id_set_all(id);
2d97a006
JR
460 if (status != LTTNG_TRACKER_ID_STATUS_OK) {
461 ERR("Invalid tracker id for track all");
462 retval = -LTTNG_ERR_INVALID;
463 goto error;
464 }
a8c3ad3e
MD
465 break;
466 case LTTNG_TRACK_NONE:
a7a533cd
JR
467 /* No ids track, so we return 0 element collection. */
468 ids = lttng_tracker_ids_create(0);
469 if (ids == NULL) {
470 PERROR("alloc list ids");
471 retval = -LTTNG_ERR_NOMEM;
472 goto end;
473 }
a8c3ad3e
MD
474 break;
475 }
a7a533cd
JR
476 *_ids = ids;
477
a8c3ad3e
MD
478end:
479 return retval;
480
481error:
a7a533cd 482 lttng_tracker_ids_destroy(ids);
a8c3ad3e
MD
483 return retval;
484}
485
486int lttng_tracker_id_set_list(struct lttng_tracker_list *tracker_list,
a7a533cd 487 const struct lttng_tracker_ids *ids)
a8c3ad3e 488{
e283e4a0 489 unsigned int i, count;
a7a533cd 490 const struct lttng_tracker_id *id;
e283e4a0 491 enum lttng_tracker_id_status status;
a7a533cd
JR
492
493 assert(tracker_list);
494 assert(ids);
a8c3ad3e
MD
495
496 lttng_tracker_list_reset(tracker_list);
e283e4a0
JR
497
498 status = lttng_tracker_ids_get_count(ids, &count);
499 if (status != LTTNG_TRACKER_ID_STATUS_OK) {
500 return LTTNG_ERR_INVALID;
501 }
a7a533cd 502
a8c3ad3e
MD
503 if (count == 0) {
504 /* Set state to "track none". */
505 tracker_list->state = LTTNG_TRACK_NONE;
506 return LTTNG_OK;
507 }
a7a533cd
JR
508
509 if (count == 1) {
510 id = lttng_tracker_ids_get_at_index(ids, 0);
511 if (lttng_tracker_id_get_type(id) == LTTNG_ID_ALL) {
512 /* Track all. */
513 return LTTNG_OK;
514 }
515 }
516
a8c3ad3e 517 for (i = 0; i < count; i++) {
a8c3ad3e 518 int ret;
a7a533cd 519 id = lttng_tracker_ids_get_at_index(ids, i);
a8c3ad3e
MD
520 ret = lttng_tracker_list_add(tracker_list, id);
521 if (ret != LTTNG_OK) {
522 return ret;
523 }
524 }
525 return LTTNG_OK;
526}
This page took 0.046731 seconds and 5 git commands to generate.