Clean-up: move global sessiond symbols out of main.o
[lttng-tools.git] / src / bin / lttng-sessiond / session.c
CommitLineData
5b74c7b1
DG
1/*
2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 *
d14d33bf
AM
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.
91d76f53 7 *
5b74c7b1
DG
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
d14d33bf 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5b74c7b1
DG
11 * GNU General Public License for more details.
12 *
d14d33bf
AM
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.
5b74c7b1
DG
16 */
17
6c1c0768 18#define _LGPL_SOURCE
6c9cc2ab 19#include <limits.h>
d022620a 20#include <inttypes.h>
5b74c7b1
DG
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
a304c14c 24#include <sys/stat.h>
f6a9efaa 25#include <urcu.h>
3d071855
MD
26#include <dirent.h>
27#include <sys/types.h>
5b74c7b1 28
990570ed 29#include <common/common.h>
db758600 30#include <common/sessiond-comm/sessiond-comm.h>
5d65beab 31#include <lttng/location-internal.h>
1e307fab 32
5b74c7b1 33#include "session.h"
23324029 34#include "utils.h"
dd73d57b 35#include "trace-ust.h"
a7333da7 36#include "timer.h"
5b74c7b1 37
8c0faa1d 38/*
b5541356 39 * NOTES:
8c0faa1d 40 *
b5541356
DG
41 * No ltt_session.lock is taken here because those data structure are widely
42 * spread across the lttng-tools code base so before caling functions below
43 * that can read/write a session, the caller MUST acquire the session lock
54d01ffb 44 * using session_lock() and session_unlock().
8c0faa1d 45 */
8c0faa1d 46
5b74c7b1 47/*
b5541356 48 * Init tracing session list.
5b74c7b1 49 *
b5541356 50 * Please see session.h for more explanation and correct usage of the list.
5b74c7b1 51 */
b5541356
DG
52static struct ltt_session_list ltt_session_list = {
53 .head = CDS_LIST_HEAD_INIT(ltt_session_list.head),
54 .lock = PTHREAD_MUTEX_INITIALIZER,
a24f7994 55 .next_uuid = 0,
b5541356 56};
5b74c7b1 57
1c1c3634
DG
58/* These characters are forbidden in a session name. Used by validate_name. */
59static const char *forbidden_name_chars = "/";
60
23324029
JD
61/* Global hash table to keep the sessions, indexed by id. */
62static struct lttng_ht *ltt_sessions_ht_by_id = NULL;
63
1c1c3634
DG
64/*
65 * Validate the session name for forbidden characters.
66 *
67 * Return 0 on success else -1 meaning a forbidden char. has been found.
68 */
69static int validate_name(const char *name)
70{
71 int ret;
72 char *tok, *tmp_name;
73
74 assert(name);
75
76 tmp_name = strdup(name);
77 if (!tmp_name) {
78 /* ENOMEM here. */
79 ret = -1;
80 goto error;
81 }
82
83 tok = strpbrk(tmp_name, forbidden_name_chars);
84 if (tok) {
85 DBG("Session name %s contains a forbidden character", name);
86 /* Forbidden character has been found. */
87 ret = -1;
88 goto error;
89 }
90 ret = 0;
91
92error:
93 free(tmp_name);
94 return ret;
95}
96
5b74c7b1 97/*
050349bb 98 * Add a ltt_session structure to the global list.
5b74c7b1 99 *
050349bb 100 * The caller MUST acquire the session list lock before.
44e96653 101 * Returns the unique identifier for the session.
5b74c7b1 102 */
d022620a 103static uint64_t add_session_list(struct ltt_session *ls)
5b74c7b1 104{
0525e9ae
DG
105 assert(ls);
106
5b74c7b1 107 cds_list_add(&ls->list, &ltt_session_list.head);
a24f7994 108 return ltt_session_list.next_uuid++;
5b74c7b1
DG
109}
110
111/*
050349bb 112 * Delete a ltt_session structure to the global list.
b5541356 113 *
050349bb 114 * The caller MUST acquire the session list lock before.
5b74c7b1
DG
115 */
116static void del_session_list(struct ltt_session *ls)
117{
0525e9ae
DG
118 assert(ls);
119
5b74c7b1 120 cds_list_del(&ls->list);
5b74c7b1
DG
121}
122
b5541356 123/*
050349bb 124 * Return a pointer to the session list.
b5541356 125 */
54d01ffb 126struct ltt_session_list *session_get_list(void)
b5541356
DG
127{
128 return &ltt_session_list;
129}
130
131/*
6c9cc2ab 132 * Acquire session list lock
b5541356 133 */
54d01ffb 134void session_lock_list(void)
b5541356 135{
6c9cc2ab 136 pthread_mutex_lock(&ltt_session_list.lock);
b5541356
DG
137}
138
71e0a100
JG
139/*
140 * Try to acquire session list lock
141 */
142int session_trylock_list(void)
143{
144 return pthread_mutex_trylock(&ltt_session_list.lock);
145}
146
b5541356 147/*
6c9cc2ab 148 * Release session list lock
b5541356 149 */
54d01ffb 150void session_unlock_list(void)
b5541356 151{
6c9cc2ab 152 pthread_mutex_unlock(&ltt_session_list.lock);
b5541356
DG
153}
154
dd73d57b
JG
155/*
156 * Get the session's consumer destination type.
157 *
158 * The caller must hold the session lock.
159 */
160enum consumer_dst_type session_get_consumer_destination_type(
161 const struct ltt_session *session)
162{
163 /*
164 * The output information is duplicated in both of those session types.
165 * Hence, it doesn't matter from which it is retrieved. However, it is
166 * possible for only one of them to be set.
167 */
168 return session->kernel_session ?
169 session->kernel_session->consumer->type :
170 session->ust_session->consumer->type;
171}
172
173/*
174 * Get the session's consumer network hostname.
175 * The caller must ensure that the destination is of type "net".
176 *
177 * The caller must hold the session lock.
178 */
179const char *session_get_net_consumer_hostname(const struct ltt_session *session)
180{
181 const char *hostname = NULL;
182 const struct consumer_output *output;
183
184 output = session->kernel_session ?
185 session->kernel_session->consumer :
186 session->ust_session->consumer;
187
188 /*
189 * hostname is assumed to be the same for both control and data
190 * connections.
191 */
192 switch (output->dst.net.control.dtype) {
193 case LTTNG_DST_IPV4:
194 hostname = output->dst.net.control.dst.ipv4;
195 break;
196 case LTTNG_DST_IPV6:
197 hostname = output->dst.net.control.dst.ipv6;
198 break;
199 default:
200 abort();
201 }
202 return hostname;
203}
204
205/*
206 * Get the session's consumer network control and data ports.
207 * The caller must ensure that the destination is of type "net".
208 *
209 * The caller must hold the session lock.
210 */
211void session_get_net_consumer_ports(const struct ltt_session *session,
212 uint16_t *control_port, uint16_t *data_port)
213{
214 const struct consumer_output *output;
215
216 output = session->kernel_session ?
217 session->kernel_session->consumer :
218 session->ust_session->consumer;
219 *control_port = output->dst.net.control.port;
220 *data_port = output->dst.net.data.port;
221}
222
5d65beab
JG
223/*
224 * Get the location of the latest trace archive produced by a rotation.
225 *
226 * The caller must hold the session lock.
227 */
228struct lttng_trace_archive_location *session_get_trace_archive_location(
229 struct ltt_session *session)
230{
231 struct lttng_trace_archive_location *location = NULL;
232
233 if (session->rotation_state != LTTNG_ROTATION_STATE_COMPLETED) {
234 goto end;
235 }
236
237 switch (session_get_consumer_destination_type(session)) {
238 case CONSUMER_DST_LOCAL:
239 location = lttng_trace_archive_location_local_create(
240 session->rotation_chunk.current_rotate_path);
241 break;
242 case CONSUMER_DST_NET:
243 {
244 const char *hostname;
245 uint16_t control_port, data_port;
246
247 hostname = session_get_net_consumer_hostname(session);
248 session_get_net_consumer_ports(session,
249 &control_port,
250 &data_port);
251 location = lttng_trace_archive_location_relay_create(
252 hostname,
253 LTTNG_TRACE_ARCHIVE_LOCATION_RELAY_PROTOCOL_TYPE_TCP,
254 control_port, data_port,
255 session->rotation_chunk.current_rotate_path);
256 break;
257 }
258 default:
259 abort();
260 }
261end:
262 return location;
263}
264
23324029
JD
265/*
266 * Allocate the ltt_sessions_ht_by_id HT.
9c6518bc
JG
267 *
268 * The session list lock must be held.
23324029
JD
269 */
270int ltt_sessions_ht_alloc(void)
271{
272 int ret = 0;
273
274 DBG("Allocating ltt_sessions_ht_by_id");
275 ltt_sessions_ht_by_id = lttng_ht_new(0, LTTNG_HT_TYPE_U64);
276 if (!ltt_sessions_ht_by_id) {
277 ret = -1;
278 ERR("Failed to allocate ltt_sessions_ht_by_id");
279 goto end;
280 }
281end:
282 return ret;
283}
284
285/*
286 * Destroy the ltt_sessions_ht_by_id HT.
9c6518bc
JG
287 *
288 * The session list lock must be held.
23324029 289 */
accdc9bf 290static void ltt_sessions_ht_destroy(void)
23324029
JD
291{
292 if (!ltt_sessions_ht_by_id) {
293 return;
294 }
295 ht_cleanup_push(ltt_sessions_ht_by_id);
296 ltt_sessions_ht_by_id = NULL;
297}
298
299/*
300 * Add a ltt_session to the ltt_sessions_ht_by_id.
301 * If unallocated, the ltt_sessions_ht_by_id HT is allocated.
302 * The session list lock must be held.
303 */
304static void add_session_ht(struct ltt_session *ls)
305{
306 int ret;
307
308 assert(ls);
309
310 if (!ltt_sessions_ht_by_id) {
311 ret = ltt_sessions_ht_alloc();
312 if (ret) {
313 ERR("Error allocating the sessions HT");
314 goto end;
315 }
316 }
317 lttng_ht_node_init_u64(&ls->node, ls->id);
318 lttng_ht_add_unique_u64(ltt_sessions_ht_by_id, &ls->node);
319
320end:
321 return;
322}
323
324/*
325 * Test if ltt_sessions_ht_by_id is empty.
326 * Return 1 if empty, 0 if not empty.
327 * The session list lock must be held.
328 */
def88971 329static int ltt_sessions_ht_empty(void)
23324029
JD
330{
331 int ret;
332
333 if (!ltt_sessions_ht_by_id) {
334 ret = 1;
335 goto end;
336 }
337
338 ret = lttng_ht_get_count(ltt_sessions_ht_by_id) ? 0 : 1;
339end:
340 return ret;
341}
342
343/*
344 * Remove a ltt_session from the ltt_sessions_ht_by_id.
345 * If empty, the ltt_sessions_ht_by_id HT is freed.
346 * The session list lock must be held.
347 */
348static void del_session_ht(struct ltt_session *ls)
349{
350 struct lttng_ht_iter iter;
351 int ret;
352
353 assert(ls);
354 assert(ltt_sessions_ht_by_id);
355
356 iter.iter.node = &ls->node.node;
357 ret = lttng_ht_del(ltt_sessions_ht_by_id, &iter);
358 assert(!ret);
359
360 if (ltt_sessions_ht_empty()) {
361 DBG("Empty ltt_sessions_ht_by_id, destroying it");
362 ltt_sessions_ht_destroy();
363 }
364}
365
b5541356 366/*
6c9cc2ab 367 * Acquire session lock
b5541356 368 */
54d01ffb 369void session_lock(struct ltt_session *session)
b5541356 370{
0525e9ae
DG
371 assert(session);
372
6c9cc2ab
DG
373 pthread_mutex_lock(&session->lock);
374}
b5541356 375
6c9cc2ab
DG
376/*
377 * Release session lock
378 */
54d01ffb 379void session_unlock(struct ltt_session *session)
6c9cc2ab 380{
0525e9ae
DG
381 assert(session);
382
6c9cc2ab 383 pthread_mutex_unlock(&session->lock);
b5541356
DG
384}
385
5b74c7b1 386/*
74babd95 387 * Return a ltt_session structure ptr that matches name. If no session found,
23324029 388 * NULL is returned. This must be called with the session list lock held using
74babd95 389 * session_lock_list and session_unlock_list.
5b74c7b1 390 */
58a1a227 391struct ltt_session *session_find_by_name(const char *name)
5b74c7b1 392{
5b74c7b1
DG
393 struct ltt_session *iter;
394
0525e9ae
DG
395 assert(name);
396
5f822d0a
DG
397 DBG2("Trying to find session by name %s", name);
398
5b74c7b1 399 cds_list_for_each_entry(iter, &ltt_session_list.head, list) {
1b110e1b 400 if (strncmp(iter->name, name, NAME_MAX) == 0) {
74babd95 401 goto found;
5b74c7b1
DG
402 }
403 }
404
74babd95 405 iter = NULL;
5b74c7b1 406
74babd95 407found:
5b74c7b1
DG
408 return iter;
409}
410
23324029
JD
411/*
412 * Return an ltt_session that matches the id. If no session is found,
413 * NULL is returned. This must be called with rcu_read_lock and
414 * session list lock held (to guarantee the lifetime of the session).
415 */
416struct ltt_session *session_find_by_id(uint64_t id)
417{
418 struct lttng_ht_node_u64 *node;
419 struct lttng_ht_iter iter;
420 struct ltt_session *ls;
421
d68ec974
JG
422 if (!ltt_sessions_ht_by_id) {
423 goto end;
424 }
425
23324029
JD
426 lttng_ht_lookup(ltt_sessions_ht_by_id, &id, &iter);
427 node = lttng_ht_iter_get_node_u64(&iter);
428 if (node == NULL) {
d68ec974 429 goto end;
23324029
JD
430 }
431 ls = caa_container_of(node, struct ltt_session, node);
432
433 DBG3("Session %" PRIu64 " found by id.", id);
434 return ls;
435
d68ec974 436end:
23324029
JD
437 DBG3("Session %" PRIu64 " NOT found by id", id);
438 return NULL;
439}
440
5b74c7b1 441/*
050349bb 442 * Delete session from the session list and free the memory.
5b74c7b1 443 *
050349bb 444 * Return -1 if no session is found. On success, return 1;
36b588ed 445 * Should *NOT* be called with RCU read-side lock held.
5b74c7b1 446 */
271933a4 447int session_destroy(struct ltt_session *session)
5b74c7b1 448{
271933a4 449 /* Safety check */
0525e9ae 450 assert(session);
271933a4 451
5c408ad8 452 DBG("Destroying session %s (id %" PRIu64 ")", session->name, session->id);
271933a4 453 del_session_list(session);
271933a4 454 pthread_mutex_destroy(&session->lock);
23324029 455 del_session_ht(session);
07424f16 456
6addfa37 457 consumer_output_put(session->consumer);
6dc3064a 458 snapshot_destroy(&session->snapshot);
271933a4 459 free(session);
5b74c7b1 460
f73fabfd 461 return LTTNG_OK;
5b74c7b1
DG
462}
463
464/*
050349bb 465 * Create a brand new session and add it to the session list.
5b74c7b1 466 */
dec56f6c 467int session_create(char *name, uid_t uid, gid_t gid)
5b74c7b1 468{
f3ed775e 469 int ret;
5b74c7b1 470 struct ltt_session *new_session;
e07ae692 471
5b74c7b1 472 /* Allocate session data structure */
ba7f0ae5 473 new_session = zmalloc(sizeof(struct ltt_session));
5b74c7b1 474 if (new_session == NULL) {
df0f840b 475 PERROR("zmalloc");
f73fabfd 476 ret = LTTNG_ERR_FATAL;
f3ed775e 477 goto error_malloc;
5b74c7b1
DG
478 }
479
f3ed775e 480 /* Define session name */
5b74c7b1 481 if (name != NULL) {
74babd95 482 if (snprintf(new_session->name, NAME_MAX, "%s", name) < 0) {
f73fabfd 483 ret = LTTNG_ERR_FATAL;
f3ed775e 484 goto error_asprintf;
5b74c7b1
DG
485 }
486 } else {
f3ed775e 487 ERR("No session name given");
f73fabfd 488 ret = LTTNG_ERR_FATAL;
f3ed775e
DG
489 goto error;
490 }
491
1c1c3634
DG
492 ret = validate_name(name);
493 if (ret < 0) {
494 ret = LTTNG_ERR_SESSION_INVALID_CHAR;
495 goto error;
496 }
497
d3e2ba59 498 ret = gethostname(new_session->hostname, sizeof(new_session->hostname));
73184835
DG
499 if (ret < 0) {
500 if (errno == ENAMETOOLONG) {
501 new_session->hostname[sizeof(new_session->hostname) - 1] = '\0';
502 } else {
503 ret = LTTNG_ERR_FATAL;
504 goto error;
505 }
d3e2ba59
JD
506 }
507
1d4b027a
DG
508 /* Init kernel session */
509 new_session->kernel_session = NULL;
f6a9efaa 510 new_session->ust_session = NULL;
1657e9bb 511
0177d773
DG
512 /* Init lock */
513 pthread_mutex_init(&new_session->lock, NULL);
5b74c7b1 514
6df2e2c9
MD
515 new_session->uid = uid;
516 new_session->gid = gid;
517
6dc3064a
DG
518 ret = snapshot_init(&new_session->snapshot);
519 if (ret < 0) {
520 ret = LTTNG_ERR_NOMEM;
521 goto error;
522 }
523
92816cc3
JG
524 new_session->rotation_pending_local = false;
525 new_session->rotation_pending_relay = false;
4f23c583 526 new_session->rotation_state = LTTNG_ROTATION_STATE_NO_ROTATION;
92816cc3
JG
527
528 new_session->rotation_pending_check_timer_enabled = false;
529 new_session->rotation_schedule_timer_enabled = false;
5c408ad8 530
b5541356 531 /* Add new session to the session list */
54d01ffb 532 session_lock_list();
a991f516 533 new_session->id = add_session_list(new_session);
23324029
JD
534 /*
535 * Add the new session to the ltt_sessions_ht_by_id.
536 * No ownership is taken by the hash table; it is merely
537 * a wrapper around the session list used for faster access
538 * by session id.
539 */
540 add_session_ht(new_session);
54d01ffb 541 session_unlock_list();
b5541356 542
a4b92340
DG
543 /*
544 * Consumer is let to NULL since the create_session_uri command will set it
545 * up and, if valid, assign it to the session.
546 */
d022620a
DG
547 DBG("Tracing session %s created with ID %" PRIu64 " by UID %d GID %d",
548 name, new_session->id, new_session->uid, new_session->gid);
b082db07 549
f73fabfd 550 return LTTNG_OK;
5b74c7b1
DG
551
552error:
f3ed775e 553error_asprintf:
0e428499 554 free(new_session);
5b74c7b1 555
f3ed775e
DG
556error_malloc:
557 return ret;
5b74c7b1 558}
2f77fc4b
DG
559
560/*
561 * Check if the UID or GID match the session. Root user has access to all
562 * sessions.
563 */
564int session_access_ok(struct ltt_session *session, uid_t uid, gid_t gid)
565{
566 assert(session);
567
568 if (uid != session->uid && gid != session->gid && uid != 0) {
569 return 0;
570 } else {
571 return 1;
572 }
573}
This page took 0.07905 seconds and 4 git commands to generate.