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