Cleanup mmap consuming
[lttng-tools.git] / liblttngctl / lttngctl.c
CommitLineData
826d496d 1/*
82a3637f
DG
2 * liblttngctl.c
3 *
4 * Linux Trace Toolkit Control Library
5 *
826d496d 6 * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
fac6795d 7 *
82a3637f
DG
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; only
11 * version 2.1 of the License.
12 *
13 * This library is distributed in the hope that it will be useful,
fac6795d 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
82a3637f
DG
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
fac6795d
DG
21 */
22
23#define _GNU_SOURCE
24#include <errno.h>
25#include <grp.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <unistd.h>
30
5b97ec60 31#include <lttng/lttng.h>
fac6795d 32
e88129fc 33#include <lttng-sessiond-comm.h>
fac6795d 34#include "lttngerr.h"
f3ed775e 35#include "lttng-share.h"
fac6795d
DG
36
37/* Socket to session daemon for communication */
38static int sessiond_socket;
39static char sessiond_sock_path[PATH_MAX];
40
41/* Communication structure to ltt-sessiond */
fac6795d 42static struct lttcomm_session_msg lsm;
5461b305 43static struct lttcomm_lttng_msg llm;
fac6795d 44
fac6795d
DG
45/* Variables */
46static char *tracing_group;
47static int connected;
48
99497cd0
MD
49/*
50 * Copy string from src to dst and enforce null terminated byte.
51 */
52static void copy_string(char *dst, const char *src, size_t len)
53{
54 if (src && dst) {
55 strncpy(dst, src, len);
56 /* Enforce the NULL terminated byte */
57 dst[len - 1] = '\0';
58 }
59}
60
fac6795d 61/*
ca95a216 62 * send_data_sessiond
fac6795d 63 *
e065084a 64 * Send lttcomm_session_msg to the session daemon.
fac6795d
DG
65 *
66 * On success, return 0
67 * On error, return error code
68 */
ca95a216 69static int send_data_sessiond(void)
fac6795d
DG
70{
71 int ret;
72
73 if (!connected) {
e065084a
DG
74 ret = -ENOTCONN;
75 goto end;
fac6795d
DG
76 }
77
78 ret = lttcomm_send_unix_sock(sessiond_socket, &lsm, sizeof(lsm));
e065084a
DG
79
80end:
81 return ret;
82}
83
84/*
ca95a216 85 * recv_data_sessiond
e065084a
DG
86 *
87 * Receive data from the sessiond socket.
88 *
89 * On success, return 0
90 * On error, return recv() error code
91 */
ca95a216 92static int recv_data_sessiond(void *buf, size_t len)
e065084a
DG
93{
94 int ret;
95
96 if (!connected) {
97 ret = -ENOTCONN;
98 goto end;
fac6795d
DG
99 }
100
ca95a216 101 ret = lttcomm_recv_unix_sock(sessiond_socket, buf, len);
fac6795d 102
e065084a 103end:
fac6795d
DG
104 return ret;
105}
106
107/*
947308c4 108 * Check if the specified group name exist.
65beb5ff
DG
109 *
110 * If yes return 0, else return -1.
947308c4
DG
111 */
112static int check_tracing_group(const char *grp_name)
113{
114 struct group *grp_tracing; /* no free(). See getgrnam(3) */
115 gid_t *grp_list;
116 int grp_list_size, grp_id, i;
117 int ret = -1;
118
119 /* Get GID of group 'tracing' */
120 grp_tracing = getgrnam(grp_name);
121 if (grp_tracing == NULL) {
122 /* NULL means not found also. getgrnam(3) */
123 if (errno != 0) {
124 perror("getgrnam");
125 }
126 goto end;
127 }
128
129 /* Get number of supplementary group IDs */
130 grp_list_size = getgroups(0, NULL);
131 if (grp_list_size < 0) {
132 perror("getgroups");
133 goto end;
134 }
135
136 /* Alloc group list of the right size */
137 grp_list = malloc(grp_list_size * sizeof(gid_t));
138 grp_id = getgroups(grp_list_size, grp_list);
139 if (grp_id < -1) {
140 perror("getgroups");
141 goto free_list;
142 }
143
144 for (i = 0; i < grp_list_size; i++) {
145 if (grp_list[i] == grp_tracing->gr_gid) {
146 ret = 0;
147 break;
148 }
149 }
150
151free_list:
152 free(grp_list);
153
154end:
155 return ret;
156}
157
158/*
65beb5ff
DG
159 * Set sessiond socket path by putting it in the global sessiond_sock_path
160 * variable.
947308c4
DG
161 */
162static int set_session_daemon_path(void)
163{
164 int ret;
165
166 /* Are we in the tracing group ? */
167 ret = check_tracing_group(tracing_group);
168 if (ret < 0 && getuid() != 0) {
99497cd0
MD
169 if (snprintf(sessiond_sock_path, PATH_MAX,
170 DEFAULT_HOME_CLIENT_UNIX_SOCK,
171 getenv("HOME")) < 0) {
947308c4
DG
172 return -ENOMEM;
173 }
174 } else {
99497cd0
MD
175 copy_string(sessiond_sock_path, DEFAULT_GLOBAL_CLIENT_UNIX_SOCK,
176 PATH_MAX);
947308c4
DG
177 }
178
179 return 0;
180}
181
65beb5ff
DG
182/*
183 * Connect to the LTTng session daemon.
184 *
185 * On success, return 0. On error, return -1.
186 */
187static int connect_sessiond(void)
188{
189 int ret;
190
191 ret = set_session_daemon_path();
192 if (ret < 0) {
193 return ret;
194 }
195
196 /* Connect to the sesssion daemon */
197 ret = lttcomm_connect_unix_sock(sessiond_sock_path);
198 if (ret < 0) {
199 return ret;
200 }
201
202 sessiond_socket = ret;
203 connected = 1;
204
205 return 0;
206}
207
208/*
209 * Clean disconnect the session daemon.
210 */
211static int disconnect_sessiond(void)
212{
213 int ret = 0;
214
215 if (connected) {
216 ret = lttcomm_close_unix_sock(sessiond_socket);
217 sessiond_socket = 0;
218 connected = 0;
219 }
220
221 return ret;
222}
223
35a6fdb7
DG
224/*
225 * Reset the session message structure.
226 */
227static void reset_session_msg(void)
228{
229 memset(&lsm, 0, sizeof(struct lttcomm_session_msg));
230}
231
65beb5ff
DG
232/*
233 * ask_sessiond
234 *
235 * Ask the session daemon a specific command and put the data into buf.
236 *
237 * Return size of data (only payload, not header).
238 */
239static int ask_sessiond(enum lttcomm_sessiond_command lct, void **buf)
240{
241 int ret;
242 size_t size;
243 void *data = NULL;
244
245 ret = connect_sessiond();
246 if (ret < 0) {
247 goto end;
248 }
249
250 lsm.cmd_type = lct;
251
252 /* Send command to session daemon */
253 ret = send_data_sessiond();
254 if (ret < 0) {
255 goto end;
256 }
257
258 /* Get header from data transmission */
259 ret = recv_data_sessiond(&llm, sizeof(llm));
260 if (ret < 0) {
261 goto end;
262 }
263
264 /* Check error code if OK */
265 if (llm.ret_code != LTTCOMM_OK) {
266 ret = -llm.ret_code;
267 goto end;
268 }
269
270 size = llm.data_size;
271 if (size == 0) {
7d29a247 272 ret = 0;
65beb5ff
DG
273 goto end;
274 }
275
276 data = (void*) malloc(size);
277
278 /* Get payload data */
279 ret = recv_data_sessiond(data, size);
280 if (ret < 0) {
281 free(data);
282 goto end;
283 }
284
285 *buf = data;
286 ret = size;
287
288end:
289 disconnect_sessiond();
35a6fdb7 290 reset_session_msg();
65beb5ff
DG
291 return ret;
292}
293
9f19cc17 294/*
eb354453
DG
295 * Copy domain to lttcomm_session_msg domain. If unknown domain, default domain
296 * will be the kernel.
9f19cc17 297 */
eb354453 298static void copy_lttng_domain(struct lttng_domain *dom)
9f19cc17 299{
eb354453
DG
300 if (dom) {
301 switch (dom->type) {
302 case LTTNG_DOMAIN_KERNEL:
303 case LTTNG_DOMAIN_UST:
304 case LTTNG_DOMAIN_UST_EXEC_NAME:
305 case LTTNG_DOMAIN_UST_PID:
306 case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN:
307 memcpy(&lsm.domain, dom, sizeof(struct lttng_domain));
308 break;
309 default:
310 lsm.domain.type = LTTNG_DOMAIN_KERNEL;
311 break;
312 }
313 }
314}
315
1df4dedd 316/*
f3ed775e 317 * Start tracing for all trace of the session.
1df4dedd 318 */
38057ed1 319int lttng_start_tracing(const char *session_name)
f3ed775e 320{
42abccdb 321 copy_string(lsm.session.name, session_name, NAME_MAX);
f3ed775e
DG
322 return ask_sessiond(LTTNG_START_TRACE, NULL);
323}
1df4dedd
DG
324
325/*
f3ed775e
DG
326 * Stop tracing for all trace of the session.
327 */
38057ed1 328int lttng_stop_tracing(const char *session_name)
f3ed775e 329{
42abccdb 330 copy_string(lsm.session.name, session_name, NAME_MAX);
f3ed775e
DG
331 return ask_sessiond(LTTNG_STOP_TRACE, NULL);
332}
333
334/*
7d29a247 335 * lttng_add_context
1df4dedd 336 */
7d29a247 337int lttng_add_context(struct lttng_domain *domain,
38057ed1
DG
338 struct lttng_event_context *ctx, const char *event_name,
339 const char *channel_name)
d65106b1 340{
eb354453
DG
341 copy_string(lsm.u.context.channel_name, channel_name, NAME_MAX);
342 copy_string(lsm.u.context.event_name, event_name, NAME_MAX);
b579acd9 343 copy_lttng_domain(domain);
d65106b1 344
eb354453
DG
345 if (ctx) {
346 memcpy(&lsm.u.context.ctx, ctx, sizeof(struct lttng_event_context));
d65106b1
DG
347 }
348
b579acd9 349 return ask_sessiond(LTTNG_ADD_CONTEXT, NULL);
d65106b1
DG
350}
351
f3ed775e 352/*
7d29a247 353 * lttng_enable_event
f3ed775e 354 */
7d29a247 355int lttng_enable_event(struct lttng_domain *domain,
38057ed1 356 struct lttng_event *ev, const char *channel_name)
1df4dedd 357{
0d0c377a 358 int ret;
33a2b854 359
94cf3c47 360 if (channel_name == NULL) {
eb354453 361 copy_string(lsm.u.enable.channel_name, DEFAULT_CHANNEL_NAME, NAME_MAX);
33a2b854 362 } else {
eb354453
DG
363 copy_string(lsm.u.enable.channel_name, channel_name, NAME_MAX);
364 }
365
0d0c377a
DG
366 copy_lttng_domain(domain);
367
368 if (ev == NULL) {
369 ret = ask_sessiond(LTTNG_ENABLE_ALL_EVENT, NULL);
370 } else {
371 memcpy(&lsm.u.enable.event, ev, sizeof(struct lttng_event));
372 ret = ask_sessiond(LTTNG_ENABLE_EVENT, NULL);
f3ed775e
DG
373 }
374
33a2b854 375 return ret;
1df4dedd
DG
376}
377
378/*
f5177a38 379 * Disable event of a channel and domain.
1df4dedd 380 */
38057ed1
DG
381int lttng_disable_event(struct lttng_domain *domain, const char *name,
382 const char *channel_name)
1df4dedd 383{
eb354453 384 int ret = -1;
1df4dedd 385
94cf3c47 386 if (channel_name == NULL) {
eb354453 387 copy_string(lsm.u.disable.channel_name, DEFAULT_CHANNEL_NAME, NAME_MAX);
f3ed775e 388 } else {
eb354453
DG
389 copy_string(lsm.u.disable.channel_name, channel_name, NAME_MAX);
390 }
391
f5177a38
DG
392 copy_lttng_domain(domain);
393
394 if (name == NULL) {
395 ret = ask_sessiond(LTTNG_DISABLE_ALL_EVENT, NULL);
396 } else {
397 copy_string(lsm.u.disable.name, name, NAME_MAX);
398 ret = ask_sessiond(LTTNG_DISABLE_EVENT, NULL);
f3ed775e
DG
399 }
400
f3ed775e 401 return ret;
1df4dedd
DG
402}
403
404/*
0d0c377a 405 * Enable channel per domain
a5c5a2bd 406 */
38057ed1
DG
407int lttng_enable_channel(struct lttng_domain *domain,
408 struct lttng_channel *chan)
a5c5a2bd 409{
eb354453
DG
410 if (chan) {
411 memcpy(&lsm.u.channel.chan, chan, sizeof(struct lttng_channel));
412 }
7d29a247 413
0d0c377a 414 copy_lttng_domain(domain);
7d29a247 415
0d0c377a 416 return ask_sessiond(LTTNG_ENABLE_CHANNEL, NULL);
8c0faa1d 417}
1df4dedd 418
2ef84c95 419/*
0b97ec54 420 * All tracing will be stopped for registered events of the channel.
2ef84c95 421 */
38057ed1 422int lttng_disable_channel(struct lttng_domain *domain, const char *name)
2ef84c95 423{
eb354453 424 copy_string(lsm.u.disable.channel_name, name, NAME_MAX);
0b97ec54 425 copy_lttng_domain(domain);
1df4dedd 426
0b97ec54 427 return ask_sessiond(LTTNG_DISABLE_CHANNEL, NULL);
ca95a216
DG
428}
429
fac6795d 430/*
2a71efd5 431 * List all available tracepoints of domain.
fac6795d 432 *
2a71efd5 433 * Return the size (bytes) of the list and set the events array.
7d29a247 434 * On error, return negative value.
fac6795d 435 */
2a71efd5
DG
436int lttng_list_tracepoints(struct lttng_domain *domain,
437 struct lttng_event **events)
fac6795d 438{
052da939 439 int ret;
fac6795d 440
eb354453 441 copy_lttng_domain(domain);
2a71efd5 442
052da939
DG
443 ret = ask_sessiond(LTTNG_LIST_TRACEPOINTS, (void **) events);
444 if (ret < 0) {
445 return ret;
eb354453 446 }
fac6795d 447
9f19cc17 448 return ret / sizeof(struct lttng_event);
fac6795d
DG
449}
450
1657e9bb 451/*
7d29a247 452 * Return a human readable string of code
1657e9bb 453 */
7d29a247 454const char *lttng_get_readable_code(int code)
1657e9bb 455{
7d29a247
DG
456 if (code > -LTTCOMM_OK) {
457 return "Ended with errors";
1657e9bb
DG
458 }
459
7d29a247 460 return lttcomm_get_readable_code(code);
1657e9bb
DG
461}
462
aaf97519 463/*
894be886 464 * Create a brand new session using name.
aaf97519 465 */
38057ed1 466int lttng_create_session(const char *name, const char *path)
aaf97519 467{
42abccdb
DG
468 copy_string(lsm.session.name, name, NAME_MAX);
469 copy_string(lsm.session.path, path, PATH_MAX);
947308c4 470 return ask_sessiond(LTTNG_CREATE_SESSION, NULL);
8028d920
DG
471}
472
473/*
8028d920
DG
474 * Destroy session using name.
475 */
38057ed1 476int lttng_destroy_session(const char *name)
8028d920 477{
42abccdb 478 copy_string(lsm.session.name, name, NAME_MAX);
947308c4 479 return ask_sessiond(LTTNG_DESTROY_SESSION, NULL);
aaf97519
DG
480}
481
57167058 482/*
57167058
DG
483 * Ask the session daemon for all available sessions.
484 *
ca95a216
DG
485 * Return number of session.
486 * On error, return negative value.
57167058 487 */
ca95a216 488int lttng_list_sessions(struct lttng_session **sessions)
57167058 489{
ca95a216 490 int ret;
57167058 491
ca95a216 492 ret = ask_sessiond(LTTNG_LIST_SESSIONS, (void**) sessions);
57167058 493 if (ret < 0) {
ca95a216 494 return ret;
57167058
DG
495 }
496
ca95a216 497 return ret / sizeof(struct lttng_session);
57167058
DG
498}
499
9f19cc17
DG
500/*
501 * List domain of a session.
502 */
503int lttng_list_domains(const char *session_name, struct lttng_domain **domains)
504{
505 int ret;
506
42abccdb 507 copy_string(lsm.session.name, session_name, NAME_MAX);
9f19cc17
DG
508 ret = ask_sessiond(LTTNG_LIST_DOMAINS, (void**) domains);
509 if (ret < 0) {
510 return ret;
511 }
512
513 return ret / sizeof(struct lttng_domain);
514}
515
516/*
517 * List channels of a session
518 */
519int lttng_list_channels(struct lttng_domain *domain,
520 const char *session_name, struct lttng_channel **channels)
521{
522 int ret;
523
42abccdb 524 copy_string(lsm.session.name, session_name, NAME_MAX);
eb354453 525 copy_lttng_domain(domain);
9f19cc17
DG
526
527 ret = ask_sessiond(LTTNG_LIST_CHANNELS, (void**) channels);
528 if (ret < 0) {
529 return ret;
530 }
531
532 return ret / sizeof(struct lttng_channel);
533}
534
535/*
536 * List events of a session channel.
537 */
538int lttng_list_events(struct lttng_domain *domain,
539 const char *session_name, const char *channel_name,
540 struct lttng_event **events)
541{
542 int ret;
543
42abccdb 544 copy_string(lsm.session.name, session_name, NAME_MAX);
eb354453
DG
545 copy_string(lsm.u.list.channel_name, channel_name, NAME_MAX);
546 copy_lttng_domain(domain);
9f19cc17
DG
547
548 ret = ask_sessiond(LTTNG_LIST_EVENTS, (void**) events);
549 if (ret < 0) {
550 return ret;
551 }
552
553 return ret / sizeof(struct lttng_event);
554}
555
7d29a247
DG
556/*
557 * Set session name for the current lsm.
558 */
38057ed1 559void lttng_set_session_name(const char *name)
e8be5f4f 560{
42abccdb 561 copy_string(lsm.session.name, name, NAME_MAX);
e8be5f4f
DG
562}
563
fac6795d
DG
564/*
565 * lttng_set_tracing_group
566 *
567 * Set tracing group variable with name. This function
568 * allocate memory pointed by tracing_group.
569 */
570int lttng_set_tracing_group(const char *name)
571{
572 if (asprintf(&tracing_group, "%s", name) < 0) {
573 return -ENOMEM;
574 }
575
576 return 0;
577}
578
d0254c7c
MD
579/*
580 * lttng_calibrate
581 */
582int lttng_calibrate(struct lttng_domain *domain,
583 struct lttng_calibrate *calibrate)
584{
585 int ret;
586
587 copy_lttng_domain(domain);
588
589 memcpy(&lsm.u.calibrate, calibrate, sizeof(struct lttng_calibrate));
590 ret = ask_sessiond(LTTNG_CALIBRATE, NULL);
591
592 return ret;
593}
594
fac6795d
DG
595/*
596 * lttng_check_session_daemon
597 *
947308c4
DG
598 * Yes, return 1
599 * No, return 0
600 * Error, return negative value
fac6795d 601 */
947308c4 602int lttng_session_daemon_alive(void)
fac6795d
DG
603{
604 int ret;
605
606 ret = set_session_daemon_path();
607 if (ret < 0) {
947308c4 608 /* Error */
fac6795d
DG
609 return ret;
610 }
611
7d8234d9 612 /* If socket exist, we check if the daemon listens to connect. */
fac6795d
DG
613 ret = access(sessiond_sock_path, F_OK);
614 if (ret < 0) {
947308c4
DG
615 /* Not alive */
616 return 0;
fac6795d
DG
617 }
618
7d8234d9
MD
619 ret = lttcomm_connect_unix_sock(sessiond_sock_path);
620 if (ret < 0) {
621 /* Not alive */
622 return 0;
623 }
624 ret = lttcomm_close_unix_sock(ret);
625 if (ret < 0)
626 perror("lttcomm_close_unix_sock");
627
947308c4
DG
628 /* Is alive */
629 return 1;
fac6795d
DG
630}
631
632/*
633 * lib constructor
634 */
635static void __attribute__((constructor)) init()
636{
637 /* Set default session group */
64a23ac4 638 lttng_set_tracing_group(LTTNG_DEFAULT_TRACING_GROUP);
fac6795d 639}
This page took 0.083828 seconds and 4 git commands to generate.