Update quickstart
[lttng-tools.git] / liblttngctl / liblttngctl.c
... / ...
CommitLineData
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 */
38static int sessiond_socket;
39static char sessiond_sock_path[PATH_MAX];
40
41/* Communication structure to ltt-sessiond */
42static struct lttcomm_session_msg lsm;
43static struct lttcomm_lttng_msg llm;
44
45/* Variables */
46static char *tracing_group;
47static 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 */
57static 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
68end:
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 */
80static 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
91end:
92 return ret;
93}
94
95/*
96 * Check if the specified group name exist.
97 *
98 * If yes return 0, else return -1.
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/*
147 * Set sessiond socket path by putting it in the global sessiond_sock_path
148 * variable.
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
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
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
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) {
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
275end:
276 disconnect_sessiond();
277 reset_session_msg();
278 return ret;
279}
280
281/*
282 * Start tracing for all trace of the session.
283 */
284int lttng_start_tracing(const char *session_name)
285{
286 strncpy(lsm.session_name, session_name, NAME_MAX);
287 return ask_sessiond(LTTNG_START_TRACE, NULL);
288}
289
290/*
291 * Stop tracing for all trace of the session.
292 */
293int lttng_stop_tracing(const char *session_name)
294{
295 strncpy(lsm.session_name, session_name, NAME_MAX);
296 return ask_sessiond(LTTNG_STOP_TRACE, NULL);
297}
298
299/*
300 * lttng_add_context
301 */
302int lttng_add_context(struct lttng_domain *domain,
303 struct lttng_event_context *ctx, const char *event_name,
304 const char *channel_name)
305{
306 int ret;
307
308 if (channel_name != NULL) {
309 strncpy(lsm.u.context.channel_name, channel_name, NAME_MAX);
310 }
311
312 if (event_name != NULL) {
313 strncpy(lsm.u.context.event_name, event_name, NAME_MAX);
314 }
315
316 memcpy(&lsm.u.context.ctx, ctx, sizeof(struct lttng_event_context));
317
318 switch (domain->type) {
319 case LTTNG_DOMAIN_KERNEL:
320 ret = ask_sessiond(LTTNG_KERNEL_ADD_CONTEXT, NULL);
321 break;
322 case LTTNG_DOMAIN_UST:
323 ret = LTTCOMM_NOT_IMPLEMENTED;
324 break;
325 default:
326 ret = LTTCOMM_UNKNOWN_DOMAIN;
327 break;
328 };
329
330 return ret;
331}
332
333/*
334 * lttng_enable_event
335 */
336int lttng_enable_event(struct lttng_domain *domain,
337 struct lttng_event *ev, const char *channel_name)
338{
339 int ret;
340
341 if (channel_name == NULL) {
342 strncpy(lsm.u.enable.channel_name, DEFAULT_CHANNEL_NAME, NAME_MAX);
343 } else {
344 strncpy(lsm.u.enable.channel_name, channel_name, NAME_MAX);
345 }
346
347 switch (domain->type) {
348 case LTTNG_DOMAIN_KERNEL:
349 if (ev == NULL) {
350 ret = ask_sessiond(LTTNG_KERNEL_ENABLE_ALL_EVENT, NULL);
351 } else {
352 memcpy(&lsm.u.enable.event, ev, sizeof(struct lttng_event));
353 ret = ask_sessiond(LTTNG_KERNEL_ENABLE_EVENT, NULL);
354 }
355 break;
356 case LTTNG_DOMAIN_UST:
357 ret = LTTCOMM_NOT_IMPLEMENTED;
358 break;
359 default:
360 ret = LTTCOMM_UNKNOWN_DOMAIN;
361 break;
362 };
363
364 return ret;
365}
366
367/*
368 * Disable an event in the kernel tracer.
369 */
370int lttng_disable_event(struct lttng_domain *domain, const char *name,
371 const char *channel_name)
372{
373 int ret;
374
375 if (channel_name == NULL) {
376 strncpy(lsm.u.disable.channel_name, DEFAULT_CHANNEL_NAME, NAME_MAX);
377 } else {
378 strncpy(lsm.u.disable.channel_name, channel_name, NAME_MAX);
379 }
380
381 switch (domain->type) {
382 case LTTNG_DOMAIN_KERNEL:
383 if (name == NULL) {
384 ret = ask_sessiond(LTTNG_KERNEL_DISABLE_ALL_EVENT, NULL);
385 } else {
386 strncpy(lsm.u.disable.name, name, NAME_MAX);
387 ret = ask_sessiond(LTTNG_KERNEL_DISABLE_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 return ret;
399}
400
401/*
402 * Enable recording for a channel for the kernel tracer.
403 */
404int lttng_enable_channel(struct lttng_domain *domain,
405 struct lttng_channel *chan)
406{
407 int ret;
408
409 memcpy(&lsm.u.channel.chan, chan, sizeof(struct lttng_channel));
410
411 switch (domain->type) {
412 case LTTNG_DOMAIN_KERNEL:
413 ret = ask_sessiond(LTTNG_KERNEL_ENABLE_CHANNEL, NULL);
414 break;
415 case LTTNG_DOMAIN_UST:
416 ret = LTTCOMM_NOT_IMPLEMENTED;
417 break;
418 default:
419 ret = LTTCOMM_UNKNOWN_DOMAIN;
420 break;
421 };
422
423 return ret;
424}
425
426/*
427 * Disable recording for the channel for the kernel tracer.
428 */
429int lttng_disable_channel(struct lttng_domain *domain, const char *name)
430{
431 int ret;
432
433 strncpy(lsm.u.disable.channel_name, name, NAME_MAX);
434
435 switch (domain->type) {
436 case LTTNG_DOMAIN_KERNEL:
437 ret = ask_sessiond(LTTNG_KERNEL_DISABLE_CHANNEL, NULL);
438 break;
439 case LTTNG_DOMAIN_UST:
440 ret = LTTCOMM_NOT_IMPLEMENTED;
441 break;
442 default:
443 ret = LTTCOMM_UNKNOWN_DOMAIN;
444 break;
445 };
446
447 return ret;
448}
449
450/*
451 * List all available events in the kernel.
452 *
453 * Return the size (bytes) of the list and set the event_list array.
454 * On error, return negative value.
455 */
456int lttng_list_events(struct lttng_domain *domain, char **event_list)
457{
458 int ret;
459
460 switch (domain->type) {
461 case LTTNG_DOMAIN_KERNEL:
462 ret = ask_sessiond(LTTNG_KERNEL_LIST_EVENTS, (void **) event_list);
463 break;
464 case LTTNG_DOMAIN_UST:
465 ret = LTTCOMM_NOT_IMPLEMENTED;
466 break;
467 default:
468 ret = LTTCOMM_UNKNOWN_DOMAIN;
469 break;
470 };
471
472 return ret;
473}
474
475/*
476 * Return a human readable string of code
477 */
478const char *lttng_get_readable_code(int code)
479{
480 if (code > -LTTCOMM_OK) {
481 return "Ended with errors";
482 }
483
484 return lttcomm_get_readable_code(code);
485}
486
487/*
488 * Create a brand new session using name.
489 */
490int lttng_create_session(const char *name, const char *path)
491{
492 strncpy(lsm.session_name, name, NAME_MAX);
493 strncpy(lsm.path, path, PATH_MAX);
494 return ask_sessiond(LTTNG_CREATE_SESSION, NULL);
495}
496
497/*
498 * Destroy session using name.
499 */
500int lttng_destroy_session(const char *name)
501{
502 strncpy(lsm.session_name, name, NAME_MAX);
503 return ask_sessiond(LTTNG_DESTROY_SESSION, NULL);
504}
505
506/*
507 * Ask the session daemon for all available sessions.
508 *
509 * Return number of session.
510 * On error, return negative value.
511 */
512int lttng_list_sessions(struct lttng_session **sessions)
513{
514 int ret;
515
516 ret = ask_sessiond(LTTNG_LIST_SESSIONS, (void**) sessions);
517 if (ret < 0) {
518 return ret;
519 }
520
521 return ret / sizeof(struct lttng_session);
522}
523
524/*
525 * Set session name for the current lsm.
526 */
527void lttng_set_session_name(const char *name)
528{
529 strncpy(lsm.session_name, name, NAME_MAX);
530}
531
532/*
533 * lttng_set_tracing_group
534 *
535 * Set tracing group variable with name. This function
536 * allocate memory pointed by tracing_group.
537 */
538int lttng_set_tracing_group(const char *name)
539{
540 if (asprintf(&tracing_group, "%s", name) < 0) {
541 return -ENOMEM;
542 }
543
544 return 0;
545}
546
547/*
548 * lttng_check_session_daemon
549 *
550 * Yes, return 1
551 * No, return 0
552 * Error, return negative value
553 */
554int lttng_session_daemon_alive(void)
555{
556 int ret;
557
558 ret = set_session_daemon_path();
559 if (ret < 0) {
560 /* Error */
561 return ret;
562 }
563
564 /* If socket exist, we consider the daemon started */
565 ret = access(sessiond_sock_path, F_OK);
566 if (ret < 0) {
567 /* Not alive */
568 return 0;
569 }
570
571 /* Is alive */
572 return 1;
573}
574
575/*
576 * lib constructor
577 */
578static void __attribute__((constructor)) init()
579{
580 /* Set default session group */
581 lttng_set_tracing_group(LTTNG_DEFAULT_TRACING_GROUP);
582}
This page took 0.024128 seconds and 4 git commands to generate.