Remove session daemon kernel list events command
[lttng-tools.git] / liblttngctl / liblttngctl.c
1 /*
2 * liblttngctl.c
3 *
4 * Linux Trace Toolkit Control Library
5 *
6 * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
7 *
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,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
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
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
31 #include <lttng/lttng.h>
32
33 #include "liblttsessiondcomm.h"
34 #include "lttngerr.h"
35 #include "lttng-share.h"
36
37 /* Socket to session daemon for communication */
38 static int sessiond_socket;
39 static char sessiond_sock_path[PATH_MAX];
40
41 /* Communication structure to ltt-sessiond */
42 static struct lttcomm_session_msg lsm;
43 static struct lttcomm_lttng_msg llm;
44
45 /* Variables */
46 static char *tracing_group;
47 static int connected;
48
49 /*
50 * send_data_sessiond
51 *
52 * Send lttcomm_session_msg to the session daemon.
53 *
54 * On success, return 0
55 * On error, return error code
56 */
57 static int send_data_sessiond(void)
58 {
59 int ret;
60
61 if (!connected) {
62 ret = -ENOTCONN;
63 goto end;
64 }
65
66 ret = lttcomm_send_unix_sock(sessiond_socket, &lsm, sizeof(lsm));
67
68 end:
69 return ret;
70 }
71
72 /*
73 * recv_data_sessiond
74 *
75 * Receive data from the sessiond socket.
76 *
77 * On success, return 0
78 * On error, return recv() error code
79 */
80 static int recv_data_sessiond(void *buf, size_t len)
81 {
82 int ret;
83
84 if (!connected) {
85 ret = -ENOTCONN;
86 goto end;
87 }
88
89 ret = lttcomm_recv_unix_sock(sessiond_socket, buf, len);
90
91 end:
92 return ret;
93 }
94
95 /*
96 * Check if the specified group name exist.
97 *
98 * If yes return 0, else return -1.
99 */
100 static 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
139 free_list:
140 free(grp_list);
141
142 end:
143 return ret;
144 }
145
146 /*
147 * Set sessiond socket path by putting it in the global sessiond_sock_path
148 * variable.
149 */
150 static 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
169 /*
170 * Connect to the LTTng session daemon.
171 *
172 * On success, return 0. On error, return -1.
173 */
174 static 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 */
198 static 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
211 /*
212 * Reset the session message structure.
213 */
214 static void reset_session_msg(void)
215 {
216 memset(&lsm, 0, sizeof(struct lttcomm_session_msg));
217 }
218
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 */
226 static 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) {
259 ret = 0;
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
275 end:
276 disconnect_sessiond();
277 reset_session_msg();
278 return ret;
279 }
280
281 /*
282 * Copy domain to lttcomm_session_msg domain. If unknown domain, default domain
283 * will be the kernel.
284 */
285 static void copy_lttng_domain(struct lttng_domain *dom)
286 {
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 */
306 static 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';
312 }
313 }
314
315 /*
316 * Start tracing for all trace of the session.
317 */
318 int lttng_start_tracing(const char *session_name)
319 {
320 copy_string(lsm.session_name, session_name, NAME_MAX);
321 return ask_sessiond(LTTNG_START_TRACE, NULL);
322 }
323
324 /*
325 * Stop tracing for all trace of the session.
326 */
327 int lttng_stop_tracing(const char *session_name)
328 {
329 copy_string(lsm.session_name, session_name, NAME_MAX);
330 return ask_sessiond(LTTNG_STOP_TRACE, NULL);
331 }
332
333 /*
334 * lttng_add_context
335 */
336 int lttng_add_context(struct lttng_domain *domain,
337 struct lttng_event_context *ctx, const char *event_name,
338 const char *channel_name)
339 {
340 int ret = -1;
341
342 copy_string(lsm.u.context.channel_name, channel_name, NAME_MAX);
343 copy_string(lsm.u.context.event_name, event_name, NAME_MAX);
344
345 if (ctx) {
346 memcpy(&lsm.u.context.ctx, ctx, sizeof(struct lttng_event_context));
347 }
348
349 if (domain) {
350 switch (domain->type) {
351 case LTTNG_DOMAIN_KERNEL:
352 ret = ask_sessiond(LTTNG_KERNEL_ADD_CONTEXT, NULL);
353 break;
354 case LTTNG_DOMAIN_UST:
355 ret = LTTCOMM_NOT_IMPLEMENTED;
356 break;
357 default:
358 ret = LTTCOMM_UNKNOWN_DOMAIN;
359 break;
360 };
361 }
362
363 return ret;
364 }
365
366 /*
367 * lttng_enable_event
368 */
369 int lttng_enable_event(struct lttng_domain *domain,
370 struct lttng_event *ev, const char *channel_name)
371 {
372 int ret = -1;
373
374 if (channel_name == NULL) {
375 copy_string(lsm.u.enable.channel_name, DEFAULT_CHANNEL_NAME, NAME_MAX);
376 } else {
377 copy_string(lsm.u.enable.channel_name, channel_name, NAME_MAX);
378 }
379
380 if (domain) {
381 switch (domain->type) {
382 case LTTNG_DOMAIN_KERNEL:
383 if (ev == NULL) {
384 ret = ask_sessiond(LTTNG_KERNEL_ENABLE_ALL_EVENT, NULL);
385 } else {
386 memcpy(&lsm.u.enable.event, ev, sizeof(struct lttng_event));
387 ret = ask_sessiond(LTTNG_KERNEL_ENABLE_EVENT, NULL);
388 }
389 break;
390 case LTTNG_DOMAIN_UST:
391 ret = LTTCOMM_NOT_IMPLEMENTED;
392 break;
393 default:
394 ret = LTTCOMM_UNKNOWN_DOMAIN;
395 break;
396 };
397 }
398
399 return ret;
400 }
401
402 /*
403 * Disable an event in the kernel tracer.
404 */
405 int lttng_disable_event(struct lttng_domain *domain, const char *name,
406 const char *channel_name)
407 {
408 int ret = -1;
409
410 if (channel_name == NULL) {
411 copy_string(lsm.u.disable.channel_name, DEFAULT_CHANNEL_NAME, NAME_MAX);
412 } else {
413 copy_string(lsm.u.disable.channel_name, channel_name, NAME_MAX);
414 }
415
416 if (domain) {
417 switch (domain->type) {
418 case LTTNG_DOMAIN_KERNEL:
419 if (name == NULL) {
420 ret = ask_sessiond(LTTNG_KERNEL_DISABLE_ALL_EVENT, NULL);
421 } else {
422 copy_string(lsm.u.disable.name, name, NAME_MAX);
423 ret = ask_sessiond(LTTNG_KERNEL_DISABLE_EVENT, NULL);
424 }
425 break;
426 case LTTNG_DOMAIN_UST:
427 ret = LTTCOMM_NOT_IMPLEMENTED;
428 break;
429 default:
430 ret = LTTCOMM_UNKNOWN_DOMAIN;
431 break;
432 };
433 }
434
435 return ret;
436 }
437
438 /*
439 * Enable recording for a channel for the kernel tracer.
440 */
441 int lttng_enable_channel(struct lttng_domain *domain,
442 struct lttng_channel *chan)
443 {
444 int ret = -1;
445
446 if (chan) {
447 memcpy(&lsm.u.channel.chan, chan, sizeof(struct lttng_channel));
448 }
449
450 if (domain) {
451 switch (domain->type) {
452 case LTTNG_DOMAIN_KERNEL:
453 ret = ask_sessiond(LTTNG_KERNEL_ENABLE_CHANNEL, NULL);
454 break;
455 case LTTNG_DOMAIN_UST:
456 ret = LTTCOMM_NOT_IMPLEMENTED;
457 break;
458 default:
459 ret = LTTCOMM_UNKNOWN_DOMAIN;
460 break;
461 };
462 }
463
464 return ret;
465 }
466
467 /*
468 * Disable recording for the channel for the kernel tracer.
469 */
470 int lttng_disable_channel(struct lttng_domain *domain, const char *name)
471 {
472 int ret = -1;
473
474 copy_string(lsm.u.disable.channel_name, name, NAME_MAX);
475
476 if (domain) {
477 switch (domain->type) {
478 case LTTNG_DOMAIN_KERNEL:
479 ret = ask_sessiond(LTTNG_KERNEL_DISABLE_CHANNEL, NULL);
480 break;
481 case LTTNG_DOMAIN_UST:
482 ret = LTTCOMM_NOT_IMPLEMENTED;
483 break;
484 default:
485 ret = LTTCOMM_UNKNOWN_DOMAIN;
486 break;
487 };
488 }
489
490 return ret;
491 }
492
493 /*
494 * List all available tracepoints of domain.
495 *
496 * Return the size (bytes) of the list and set the events array.
497 * On error, return negative value.
498 */
499 int lttng_list_tracepoints(struct lttng_domain *domain,
500 struct lttng_event **events)
501 {
502 int ret;
503
504 copy_lttng_domain(domain);
505
506 ret = ask_sessiond(LTTNG_LIST_TRACEPOINTS, (void **) events);
507 if (ret < 0) {
508 return ret;
509 }
510
511 return ret / sizeof(struct lttng_event);
512 }
513
514 /*
515 * Return a human readable string of code
516 */
517 const char *lttng_get_readable_code(int code)
518 {
519 if (code > -LTTCOMM_OK) {
520 return "Ended with errors";
521 }
522
523 return lttcomm_get_readable_code(code);
524 }
525
526 /*
527 * Create a brand new session using name.
528 */
529 int lttng_create_session(const char *name, const char *path)
530 {
531 copy_string(lsm.session_name, name, NAME_MAX);
532 copy_string(lsm.path, path, PATH_MAX);
533 return ask_sessiond(LTTNG_CREATE_SESSION, NULL);
534 }
535
536 /*
537 * Destroy session using name.
538 */
539 int lttng_destroy_session(const char *name)
540 {
541 copy_string(lsm.session_name, name, NAME_MAX);
542 return ask_sessiond(LTTNG_DESTROY_SESSION, NULL);
543 }
544
545 /*
546 * Ask the session daemon for all available sessions.
547 *
548 * Return number of session.
549 * On error, return negative value.
550 */
551 int lttng_list_sessions(struct lttng_session **sessions)
552 {
553 int ret;
554
555 ret = ask_sessiond(LTTNG_LIST_SESSIONS, (void**) sessions);
556 if (ret < 0) {
557 return ret;
558 }
559
560 return ret / sizeof(struct lttng_session);
561 }
562
563 /*
564 * List domain of a session.
565 */
566 int lttng_list_domains(const char *session_name, struct lttng_domain **domains)
567 {
568 int ret;
569
570 copy_string(lsm.session_name, session_name, NAME_MAX);
571 ret = ask_sessiond(LTTNG_LIST_DOMAINS, (void**) domains);
572 if (ret < 0) {
573 return ret;
574 }
575
576 return ret / sizeof(struct lttng_domain);
577 }
578
579 /*
580 * List channels of a session
581 */
582 int lttng_list_channels(struct lttng_domain *domain,
583 const char *session_name, struct lttng_channel **channels)
584 {
585 int ret;
586
587 copy_string(lsm.session_name, session_name, NAME_MAX);
588 copy_lttng_domain(domain);
589
590 ret = ask_sessiond(LTTNG_LIST_CHANNELS, (void**) channels);
591 if (ret < 0) {
592 return ret;
593 }
594
595 return ret / sizeof(struct lttng_channel);
596 }
597
598 /*
599 * List events of a session channel.
600 */
601 int lttng_list_events(struct lttng_domain *domain,
602 const char *session_name, const char *channel_name,
603 struct lttng_event **events)
604 {
605 int ret;
606
607 copy_string(lsm.session_name, session_name, NAME_MAX);
608 copy_string(lsm.u.list.channel_name, channel_name, NAME_MAX);
609 copy_lttng_domain(domain);
610
611 ret = ask_sessiond(LTTNG_LIST_EVENTS, (void**) events);
612 if (ret < 0) {
613 return ret;
614 }
615
616 return ret / sizeof(struct lttng_event);
617 }
618
619 /*
620 * Set session name for the current lsm.
621 */
622 void lttng_set_session_name(const char *name)
623 {
624 copy_string(lsm.session_name, name, NAME_MAX);
625 }
626
627 /*
628 * lttng_set_tracing_group
629 *
630 * Set tracing group variable with name. This function
631 * allocate memory pointed by tracing_group.
632 */
633 int lttng_set_tracing_group(const char *name)
634 {
635 if (asprintf(&tracing_group, "%s", name) < 0) {
636 return -ENOMEM;
637 }
638
639 return 0;
640 }
641
642 /*
643 * lttng_check_session_daemon
644 *
645 * Yes, return 1
646 * No, return 0
647 * Error, return negative value
648 */
649 int lttng_session_daemon_alive(void)
650 {
651 int ret;
652
653 ret = set_session_daemon_path();
654 if (ret < 0) {
655 /* Error */
656 return ret;
657 }
658
659 /* If socket exist, we consider the daemon started */
660 ret = access(sessiond_sock_path, F_OK);
661 if (ret < 0) {
662 /* Not alive */
663 return 0;
664 }
665
666 /* Is alive */
667 return 1;
668 }
669
670 /*
671 * lib constructor
672 */
673 static void __attribute__((constructor)) init()
674 {
675 /* Set default session group */
676 lttng_set_tracing_group(LTTNG_DEFAULT_TRACING_GROUP);
677 }
This page took 0.043003 seconds and 5 git commands to generate.