Fix all strncpy() usage: need to set a final \0 character at the end
[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 <lttng/lttng-sessiond-comm.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 * Copy string from src to dst and enforce null terminated byte.
51 */
52 static 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
61 /*
62 * send_data_sessiond
63 *
64 * Send lttcomm_session_msg to the session daemon.
65 *
66 * On success, return 0
67 * On error, return error code
68 */
69 static int send_data_sessiond(void)
70 {
71 int ret;
72
73 if (!connected) {
74 ret = -ENOTCONN;
75 goto end;
76 }
77
78 ret = lttcomm_send_unix_sock(sessiond_socket, &lsm, sizeof(lsm));
79
80 end:
81 return ret;
82 }
83
84 /*
85 * recv_data_sessiond
86 *
87 * Receive data from the sessiond socket.
88 *
89 * On success, return 0
90 * On error, return recv() error code
91 */
92 static int recv_data_sessiond(void *buf, size_t len)
93 {
94 int ret;
95
96 if (!connected) {
97 ret = -ENOTCONN;
98 goto end;
99 }
100
101 ret = lttcomm_recv_unix_sock(sessiond_socket, buf, len);
102
103 end:
104 return ret;
105 }
106
107 /*
108 * Check if the specified group name exist.
109 *
110 * If yes return 0, else return -1.
111 */
112 static 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
151 free_list:
152 free(grp_list);
153
154 end:
155 return ret;
156 }
157
158 /*
159 * Set sessiond socket path by putting it in the global sessiond_sock_path
160 * variable.
161 */
162 static 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) {
169 if (snprintf(sessiond_sock_path, PATH_MAX,
170 DEFAULT_HOME_CLIENT_UNIX_SOCK,
171 getenv("HOME")) < 0) {
172 return -ENOMEM;
173 }
174 } else {
175 copy_string(sessiond_sock_path, DEFAULT_GLOBAL_CLIENT_UNIX_SOCK,
176 PATH_MAX);
177 }
178
179 return 0;
180 }
181
182 /*
183 * Connect to the LTTng session daemon.
184 *
185 * On success, return 0. On error, return -1.
186 */
187 static 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 */
211 static 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
224 /*
225 * Reset the session message structure.
226 */
227 static void reset_session_msg(void)
228 {
229 memset(&lsm, 0, sizeof(struct lttcomm_session_msg));
230 }
231
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 */
239 static 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) {
272 ret = 0;
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
288 end:
289 disconnect_sessiond();
290 reset_session_msg();
291 return ret;
292 }
293
294 /*
295 * Copy domain to lttcomm_session_msg domain. If unknown domain, default domain
296 * will be the kernel.
297 */
298 static void copy_lttng_domain(struct lttng_domain *dom)
299 {
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
316 /*
317 * Start tracing for all trace of the session.
318 */
319 int lttng_start_tracing(const char *session_name)
320 {
321 copy_string(lsm.session.name, session_name, NAME_MAX);
322 return ask_sessiond(LTTNG_START_TRACE, NULL);
323 }
324
325 /*
326 * Stop tracing for all trace of the session.
327 */
328 int lttng_stop_tracing(const char *session_name)
329 {
330 copy_string(lsm.session.name, session_name, NAME_MAX);
331 return ask_sessiond(LTTNG_STOP_TRACE, NULL);
332 }
333
334 /*
335 * lttng_add_context
336 */
337 int lttng_add_context(struct lttng_domain *domain,
338 struct lttng_event_context *ctx, const char *event_name,
339 const char *channel_name)
340 {
341 copy_string(lsm.u.context.channel_name, channel_name, NAME_MAX);
342 copy_string(lsm.u.context.event_name, event_name, NAME_MAX);
343 copy_lttng_domain(domain);
344
345 if (ctx) {
346 memcpy(&lsm.u.context.ctx, ctx, sizeof(struct lttng_event_context));
347 }
348
349 return ask_sessiond(LTTNG_ADD_CONTEXT, NULL);
350 }
351
352 /*
353 * lttng_enable_event
354 */
355 int lttng_enable_event(struct lttng_domain *domain,
356 struct lttng_event *ev, const char *channel_name)
357 {
358 int ret;
359
360 if (channel_name == NULL) {
361 copy_string(lsm.u.enable.channel_name, DEFAULT_CHANNEL_NAME, NAME_MAX);
362 } else {
363 copy_string(lsm.u.enable.channel_name, channel_name, NAME_MAX);
364 }
365
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);
373 }
374
375 return ret;
376 }
377
378 /*
379 * Disable event of a channel and domain.
380 */
381 int lttng_disable_event(struct lttng_domain *domain, const char *name,
382 const char *channel_name)
383 {
384 int ret = -1;
385
386 if (channel_name == NULL) {
387 copy_string(lsm.u.disable.channel_name, DEFAULT_CHANNEL_NAME, NAME_MAX);
388 } else {
389 copy_string(lsm.u.disable.channel_name, channel_name, NAME_MAX);
390 }
391
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);
399 }
400
401 return ret;
402 }
403
404 /*
405 * Enable channel per domain
406 */
407 int lttng_enable_channel(struct lttng_domain *domain,
408 struct lttng_channel *chan)
409 {
410 if (chan) {
411 memcpy(&lsm.u.channel.chan, chan, sizeof(struct lttng_channel));
412 }
413
414 copy_lttng_domain(domain);
415
416 return ask_sessiond(LTTNG_ENABLE_CHANNEL, NULL);
417 }
418
419 /*
420 * All tracing will be stopped for registered events of the channel.
421 */
422 int lttng_disable_channel(struct lttng_domain *domain, const char *name)
423 {
424 copy_string(lsm.u.disable.channel_name, name, NAME_MAX);
425 copy_lttng_domain(domain);
426
427 return ask_sessiond(LTTNG_DISABLE_CHANNEL, NULL);
428 }
429
430 /*
431 * List all available tracepoints of domain.
432 *
433 * Return the size (bytes) of the list and set the events array.
434 * On error, return negative value.
435 */
436 int lttng_list_tracepoints(struct lttng_domain *domain,
437 struct lttng_event **events)
438 {
439 int ret;
440
441 copy_lttng_domain(domain);
442
443 ret = ask_sessiond(LTTNG_LIST_TRACEPOINTS, (void **) events);
444 if (ret < 0) {
445 return ret;
446 }
447
448 return ret / sizeof(struct lttng_event);
449 }
450
451 /*
452 * Return a human readable string of code
453 */
454 const char *lttng_get_readable_code(int code)
455 {
456 if (code > -LTTCOMM_OK) {
457 return "Ended with errors";
458 }
459
460 return lttcomm_get_readable_code(code);
461 }
462
463 /*
464 * Create a brand new session using name.
465 */
466 int lttng_create_session(const char *name, const char *path)
467 {
468 copy_string(lsm.session.name, name, NAME_MAX);
469 copy_string(lsm.session.path, path, PATH_MAX);
470 return ask_sessiond(LTTNG_CREATE_SESSION, NULL);
471 }
472
473 /*
474 * Destroy session using name.
475 */
476 int lttng_destroy_session(const char *name)
477 {
478 copy_string(lsm.session.name, name, NAME_MAX);
479 return ask_sessiond(LTTNG_DESTROY_SESSION, NULL);
480 }
481
482 /*
483 * Ask the session daemon for all available sessions.
484 *
485 * Return number of session.
486 * On error, return negative value.
487 */
488 int lttng_list_sessions(struct lttng_session **sessions)
489 {
490 int ret;
491
492 ret = ask_sessiond(LTTNG_LIST_SESSIONS, (void**) sessions);
493 if (ret < 0) {
494 return ret;
495 }
496
497 return ret / sizeof(struct lttng_session);
498 }
499
500 /*
501 * List domain of a session.
502 */
503 int lttng_list_domains(const char *session_name, struct lttng_domain **domains)
504 {
505 int ret;
506
507 copy_string(lsm.session.name, session_name, NAME_MAX);
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 */
519 int lttng_list_channels(struct lttng_domain *domain,
520 const char *session_name, struct lttng_channel **channels)
521 {
522 int ret;
523
524 copy_string(lsm.session.name, session_name, NAME_MAX);
525 copy_lttng_domain(domain);
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 */
538 int 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
544 copy_string(lsm.session.name, session_name, NAME_MAX);
545 copy_string(lsm.u.list.channel_name, channel_name, NAME_MAX);
546 copy_lttng_domain(domain);
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
556 /*
557 * Set session name for the current lsm.
558 */
559 void lttng_set_session_name(const char *name)
560 {
561 copy_string(lsm.session.name, name, NAME_MAX);
562 }
563
564 /*
565 * lttng_set_tracing_group
566 *
567 * Set tracing group variable with name. This function
568 * allocate memory pointed by tracing_group.
569 */
570 int 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
579 /*
580 * lttng_calibrate
581 */
582 int 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
595 /*
596 * lttng_check_session_daemon
597 *
598 * Yes, return 1
599 * No, return 0
600 * Error, return negative value
601 */
602 int lttng_session_daemon_alive(void)
603 {
604 int ret;
605
606 ret = set_session_daemon_path();
607 if (ret < 0) {
608 /* Error */
609 return ret;
610 }
611
612 /* If socket exist, we check if the daemon listens to connect. */
613 ret = access(sessiond_sock_path, F_OK);
614 if (ret < 0) {
615 /* Not alive */
616 return 0;
617 }
618
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
628 /* Is alive */
629 return 1;
630 }
631
632 /*
633 * lib constructor
634 */
635 static void __attribute__((constructor)) init()
636 {
637 /* Set default session group */
638 lttng_set_tracing_group(LTTNG_DEFAULT_TRACING_GROUP);
639 }
This page took 0.041711 seconds and 4 git commands to generate.