b523960c33063be98e5bdf35fc9359fcdf76835f
[lttng-tools.git] / lttng / lttng.c
1 /*
2 * Copyright (c) 2011 David Goulet <david.goulet@polymtl.ca>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #define _GNU_SOURCE
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <getopt.h>
23 #include <grp.h>
24 #include <limits.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <sys/wait.h>
31 #include <unistd.h>
32
33 #include <lttng/lttng.h>
34
35 #include "lttngerr.h"
36 #include "options.h"
37
38 /* Variables */
39 static char *progname;
40 static char *session_name;
41 static uuid_t current_uuid;
42 static int auto_session;
43 static int auto_trace;
44
45 /* Prototypes */
46 static int process_client_opt(void);
47 static int process_opt_list_apps(void);
48 static int process_opt_list_sessions(void);
49 static int process_opt_list_traces(void);
50 static int process_opt_kernel_list_events(void);
51 static int process_opt_create_session(void);
52 static int process_kernel_create_trace(void);
53 static int process_opt_kernel_event(void);
54 static int process_kernel_start_trace(void);
55 static int set_session_uuid(void);
56 static void sighandler(int sig);
57 static int set_signal_handler(void);
58 static int validate_options(void);
59 static char *get_cmdline_by_pid(pid_t pid);
60 static void set_opt_session_info(void);
61
62 /*
63 * start_client
64 *
65 * Process client request from the command line
66 * options. Every tracing action is done by the
67 * liblttngctl API.
68 */
69 static int process_client_opt(void)
70 {
71 int ret;
72
73 set_opt_session_info();
74
75 if (opt_list_apps) {
76 ret = process_opt_list_apps();
77 if (ret < 0) {
78 goto end;
79 }
80 goto error;
81 }
82
83 if (opt_list_session) {
84 ret = process_opt_list_sessions();
85 if (ret < 0) {
86 goto end;
87 }
88 goto error;
89 }
90
91 if (opt_list_events) {
92 if (opt_trace_kernel) {
93 ret = process_opt_kernel_list_events();
94 if (ret < 0) {
95 goto end;
96 }
97 } else if (opt_trace_pid != 0) {
98 // TODO
99 }
100 goto error;
101 }
102
103 /* Session creation or auto session set on */
104 if (auto_session || opt_create_session) {
105 DBG("Creating a new session");
106 ret = process_opt_create_session();
107 if (ret < 0) {
108 goto end;
109 }
110 }
111
112 ret = set_session_uuid();
113 if (ret < 0) {
114 ERR("Session %s not found", opt_session_name);
115 goto error;
116 }
117
118 if (opt_destroy_session) {
119 ret = lttng_destroy_session(&current_uuid);
120 if (ret < 0) {
121 goto end;
122 }
123 MSG("Session %s destroyed.", opt_session_name);
124 }
125
126 if (opt_list_traces) {
127 ret = process_opt_list_traces();
128 if (ret < 0) {
129 goto end;
130 }
131 }
132
133 /*
134 * Action on traces (kernel or/and userspace).
135 */
136
137 if (opt_trace_kernel) {
138 if (auto_trace || opt_create_trace) {
139 DBG("Creating a kernel trace");
140 ret = process_kernel_create_trace();
141 if (ret < 0) {
142 goto end;
143 }
144 }
145
146 if (opt_event_list != NULL || opt_enable_all_event) {
147 ret = process_opt_kernel_event();
148 if (ret < 0) {
149 goto end;
150 }
151 }
152
153 if (auto_trace || opt_start_trace) {
154 DBG("Starting kernel tracing");
155 ret = process_kernel_start_trace();
156 if (ret < 0) {
157 goto end;
158 }
159 }
160
161 if (opt_stop_trace) {
162 DBG("Stopping kernel tracing");
163 ret = lttng_kernel_stop_tracing();
164 if (ret < 0) {
165 goto end;
166 }
167 }
168 }
169
170 if (opt_trace_pid != 0) {
171 if (auto_trace || opt_create_trace) {
172 DBG("Create a userspace trace for pid %d", opt_trace_pid);
173 ret = lttng_ust_create_trace(opt_trace_pid);
174 if (ret < 0) {
175 goto end;
176 }
177 MSG("Trace created successfully!");
178 }
179
180 if (auto_trace || opt_start_trace) {
181 DBG("Start trace for pid %d", opt_trace_pid);
182 ret = lttng_ust_start_trace(opt_trace_pid);
183 if (ret < 0) {
184 goto end;
185 }
186 MSG("Trace started successfully!");
187 } else if (opt_stop_trace) {
188 DBG("Stop trace for pid %d", opt_trace_pid);
189 ret = lttng_ust_stop_trace(opt_trace_pid);
190 if (ret < 0) {
191 goto end;
192 }
193 MSG("Trace stopped successfully!");
194 }
195
196 }
197
198 return 0;
199
200 end:
201 ERR("%s", lttng_get_readable_code(ret));
202 error: /* fall through */
203 return ret;
204 }
205
206 /*
207 * process_kernel_start_trace
208 *
209 * Start a kernel trace.
210 */
211 static int process_kernel_start_trace(void)
212 {
213 int ret;
214
215 ret = lttng_kernel_create_stream();
216 if (ret < 0) {
217 goto error;
218 }
219
220 ret = lttng_kernel_start_tracing();
221 if (ret < 0) {
222 goto error;
223 }
224
225 MSG("Kernel tracing started");
226
227 return 0;
228
229 error:
230 return ret;
231 }
232
233 /*
234 * process_kernel_create_trace
235 *
236 * Create a kernel trace.
237 */
238 static int process_kernel_create_trace(void)
239 {
240 int ret;
241
242 /* Setup kernel session */
243 ret = lttng_kernel_create_session();
244 if (ret < 0) {
245 goto error;
246 }
247
248 /* Create an empty channel (with no event) */
249 ret = lttng_kernel_create_channel();
250 if (ret < 0) {
251 goto error;
252 }
253
254 /* Opening metadata for session */
255 ret = lttng_kernel_open_metadata();
256 if (ret < 0) {
257 goto error;
258 }
259
260 return 0;
261
262 error:
263 return ret;
264 }
265
266 /*
267 * process_opt_kernel_list_events
268 *
269 * Ask for all trace events in the kernel and pretty print them.
270 */
271 static int process_opt_kernel_list_events(void)
272 {
273 int ret, pos, size;
274 char *event_list, *event, *ptr;
275
276 DBG("Getting all tracing events");
277
278 ret = lttng_kernel_list_events(&event_list);
279 if (ret < 0) {
280 ERR("Unable to list events.");
281 return ret;
282 }
283
284 MSG("Kernel tracepoints:\n-------------");
285
286 ptr = event_list;
287 while ((size = sscanf(ptr, "event { name = %m[^;]; };%n\n", &event, &pos)) == 1) {
288 MSG(" - %s", event);
289 /* Move pointer to the next line */
290 ptr += pos + 1;
291 free(event);
292 }
293
294 free(event_list);
295
296 return 0;
297 }
298
299 /*
300 * process_opt_kernel_event
301 *
302 * Enable kernel event from the command line list given.
303 */
304 static int process_opt_kernel_event(void)
305 {
306 int ret;
307 char *event_name;
308
309 if (opt_enable_all_event) {
310 ret = lttng_kernel_enable_event(NULL);
311 if (ret < 0) {
312 ERR("%s", lttng_get_readable_code(ret));
313 } else {
314 MSG("All kernel event enabled");
315 }
316
317 goto end;
318 }
319
320 event_name = strtok(opt_event_list, ",");
321 while (event_name != NULL) {
322 DBG("Enabling kernel event %s", event_name);
323 ret = lttng_kernel_enable_event(event_name);
324 if (ret < 0) {
325 ERR("%s %s", lttng_get_readable_code(ret), event_name);
326 } else {
327 MSG("Kernel event %s enabled.", event_name);
328 }
329 /* Next event */
330 event_name = strtok(NULL, ",");
331 }
332
333 end:
334 return 0;
335 }
336
337 /*
338 * set_opt_session_info
339 *
340 * Setup session_name, current_uuid, short_str_uuid and
341 * long_str_uuid using the command line options.
342 */
343 static void set_opt_session_info(void)
344 {
345 if (opt_session_name != NULL) {
346 session_name = strndup(opt_session_name, NAME_MAX);
347 DBG("Session name set to %s", session_name);
348 }
349 }
350
351 /*
352 * set_session_uuid
353 *
354 * Set current session uuid to the current flow of command(s) using the
355 * session_name.
356 */
357 static int set_session_uuid(void)
358 {
359 int ret, count, i, found = 0;
360 struct lttng_session *sessions;
361
362 if (!uuid_is_null(current_uuid)) {
363 lttng_set_current_session_uuid(&current_uuid);
364 goto end;
365 }
366
367 count = lttng_list_sessions(&sessions);
368 if (count < 0) {
369 ret = count;
370 goto error;
371 }
372
373 for (i = 0; i < count; i++) {
374 if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) {
375 lttng_set_current_session_uuid(&sessions[i].uuid);
376 uuid_copy(current_uuid, sessions[i].uuid);
377 found = 1;
378 break;
379 }
380 }
381
382 free(sessions);
383
384 if (!found) {
385 return -1;
386 }
387
388 end:
389 DBG("Session UUID set");
390 return 0;
391
392 error:
393 return ret;
394 }
395
396 /*
397 * process_opt_list_traces
398 *
399 * Get list of all traces for a specific session uuid.
400 */
401 static int process_opt_list_traces(void)
402 {
403 int ret, i;
404 struct lttng_trace *traces;
405
406 ret = lttng_list_traces(&current_uuid, &traces);
407 DBG("Number of traces to list %d", ret);
408 if (ret < 0) {
409 goto error;
410 }
411
412 /* No traces */
413 if (ret == 0) {
414 MSG("No traces found.");
415 goto error;
416 }
417
418 MSG("Userspace traces:");
419 for (i = 0; i < ret; i++) {
420 if (traces[i].type == USERSPACE) {
421 MSG("\t%d) %s (pid: %d): %s",
422 i, traces[i].name, traces[i].pid,
423 get_cmdline_by_pid(traces[i].pid));
424 } else {
425 break;
426 }
427 }
428
429 MSG("Kernel traces:");
430 for (;i < ret; i++) {
431 if (traces[i].type == KERNEL) {
432 MSG("\t%d) %s", i, traces[i].name);
433 }
434 }
435
436 free(traces);
437
438 error:
439 return ret;
440 }
441
442 /*
443 * process_opt_create_session
444 *
445 * Create a new session using the name pass
446 * to the command line.
447 */
448 static int process_opt_create_session(void)
449 {
450 int ret;
451 char name[NAME_MAX];
452 time_t rawtime;
453 struct tm *timeinfo;
454
455 /* Auto session name creation */
456 if (opt_session_name == NULL) {
457 time(&rawtime);
458 timeinfo = localtime(&rawtime);
459 strftime(name, sizeof(name), "auto-%Y%m%d-%H%M%S", timeinfo);
460 session_name = strndup(name, sizeof(name));
461 DBG("Auto session name set to %s", session_name);
462 }
463
464 ret = lttng_create_session(session_name);
465 if (ret < 0) {
466 goto error;
467 }
468
469 MSG("Session created: %s", session_name);
470
471 error:
472 return ret;
473 }
474
475 /*
476 * process_opt_list_sessions
477 *
478 * Get the list of available sessions from
479 * the session daemon and print it to user.
480 */
481 static int process_opt_list_sessions(void)
482 {
483 int ret, count, i;
484 struct lttng_session *sessions;
485
486 count = lttng_list_sessions(&sessions);
487 DBG("Session count %d", count);
488 if (count < 0) {
489 ret = count;
490 goto error;
491 }
492
493 MSG("Available sessions (UUIDs):");
494 for (i = 0; i < count; i++) {
495 MSG(" %d) %s", i+1, sessions[i].name);
496 }
497
498 free(sessions);
499 MSG("\nTo select a session, use -s, --session UUID.");
500
501 return 0;
502
503 error:
504 return ret;
505 }
506
507 /*
508 * process_opt_list_apps
509 *
510 * Get the UST traceable pid list and print
511 * them to the user.
512 */
513 static int process_opt_list_apps(void)
514 {
515 int i, ret, count;
516 pid_t *pids;
517 char *cmdline;
518
519 count = lttng_ust_list_apps(&pids);
520 if (count < 0) {
521 ret = count;
522 goto error;
523 }
524
525 MSG("LTTng UST traceable application [name (pid)]:");
526 for (i=0; i < count; i++) {
527 cmdline = get_cmdline_by_pid(pids[i]);
528 if (cmdline == NULL) {
529 MSG("\t(not running) (%d)", pids[i]);
530 continue;
531 }
532 MSG("\t%s (%d)", cmdline, pids[i]);
533 free(cmdline);
534 }
535
536 /* Allocated by lttng_ust_list_apps() */
537 free(pids);
538
539 return 0;
540
541 error:
542 return ret;
543 }
544
545 /*
546 * get_cmdline_by_pid
547 *
548 * Get command line from /proc for a specific pid.
549 *
550 * On success, return an allocated string pointer pointing to
551 * the proc cmdline.
552 * On error, return NULL.
553 */
554 static char *get_cmdline_by_pid(pid_t pid)
555 {
556 int ret;
557 FILE *fp;
558 char *cmdline = NULL;
559 char path[24]; /* Can't go bigger than /proc/65535/cmdline */
560
561 snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
562 fp = fopen(path, "r");
563 if (fp == NULL) {
564 goto end;
565 }
566
567 /* Caller must free() *cmdline */
568 cmdline = malloc(PATH_MAX);
569 ret = fread(cmdline, 1, PATH_MAX, fp);
570 fclose(fp);
571
572 end:
573 return cmdline;
574 }
575
576 /*
577 * validate_options
578 *
579 * Make sure that all options passed to the command line are compatible with
580 * each others.
581 *
582 * On error, return -1
583 * On success, return 0
584 */
585 static int validate_options(void)
586 {
587 /* If listing options, jump validation */
588 if (opt_list_apps || opt_list_session) {
589 goto end;
590 }
591 /* Conflicting command */
592 if (opt_start_trace && opt_stop_trace) {
593 ERR("Can't use --start and --stop together.");
594 goto error;
595 /* If no PID specified and trace_kernel is off */
596 } else if ((opt_trace_pid == 0 && !opt_trace_kernel) &&
597 (opt_create_trace || opt_start_trace || opt_stop_trace || opt_destroy_trace)) {
598 ERR("Please specify for which tracer (-k or -p PID).");
599 goto error;
600 /* List traces, we need a session name */
601 } else if (opt_list_traces && opt_session_name == NULL) {
602 ERR("Can't use -t without -s, --session option.");
603 goto error;
604 /* Can't set event for both kernel and userspace at the same time */
605 } else if (opt_event_list != NULL && (opt_trace_kernel && opt_trace_pid)) {
606 ERR("Please don't use --event for both kernel and userspace.\nOne at a time to enable events.");
607 goto error;
608 /* Don't need a trace name for kernel tracig */
609 } else if (opt_trace_name != NULL && opt_trace_kernel) {
610 ERR("For action on a kernel trace, please don't specify a trace name.");
611 goto error;
612 } else if (opt_destroy_trace && opt_session_name == NULL) {
613 ERR("Please specify a session in order to destroy a trace");
614 goto error;
615 } else if (opt_create_trace || opt_destroy_trace) {
616 /* Both kernel and user-space are denied for these options */
617 if (opt_trace_pid != 0 && opt_trace_kernel) {
618 ERR("Kernel and user-space trace creation and destruction can't be used together.");
619 goto error;
620 /* Need a trace name for user-space tracing */
621 } else if (opt_trace_name == NULL && opt_trace_pid != 0) {
622 ERR("Please specify a trace name for user-space tracing");
623 goto error;
624 }
625 } else if (opt_stop_trace && opt_trace_pid != 0 && opt_trace_name == NULL) {
626 ERR("Please specify a trace name for user-space tracing");
627 goto error;
628 } else if (opt_stop_trace && opt_session_name == NULL) {
629 ERR("Please specify a session to stop tracing");
630 goto error;
631 }
632
633 /* If start trace, auto start tracing */
634 if (opt_start_trace || opt_event_list != NULL || opt_enable_all_event) {
635 DBG("Requesting auto tracing");
636 auto_trace = 1;
637 }
638
639 /* If no session, auto create one */
640 if (opt_session_name == NULL) {
641 DBG("Requesting an auto session creation");
642 auto_session = 1;
643 }
644
645 end:
646 return 0;
647
648 error:
649 return -1;
650 }
651
652 /*
653 * spawn_sessiond
654 *
655 * Spawn a session daemon by forking and execv.
656 */
657 static int spawn_sessiond(char *pathname)
658 {
659 int ret = 0;
660 pid_t pid;
661
662 MSG("Spawning session daemon");
663 pid = fork();
664 if (pid == 0) {
665 /*
666 * Spawn session daemon and tell
667 * it to signal us when ready.
668 */
669 execlp(pathname, "ltt-sessiond", "--sig-parent", "--quiet", NULL);
670 /* execlp only returns if error happened */
671 if (errno == ENOENT) {
672 ERR("No session daemon found. Use --sessiond-path.");
673 } else {
674 perror("execlp");
675 }
676 kill(getppid(), SIGTERM); /* unpause parent */
677 exit(EXIT_FAILURE);
678 } else if (pid > 0) {
679 /* Wait for ltt-sessiond to start */
680 pause();
681 goto end;
682 } else {
683 perror("fork");
684 ret = -1;
685 goto end;
686 }
687
688 end:
689 return ret;
690 }
691
692 /*
693 * check_ltt_sessiond
694 *
695 * Check if the session daemon is available using
696 * the liblttngctl API for the check. If not, try to
697 * spawn a daemon.
698 */
699 static int check_ltt_sessiond(void)
700 {
701 int ret;
702 char *pathname = NULL, *alloc_pathname = NULL;
703
704 ret = lttng_session_daemon_alive();
705 if (ret == 0) { /* not alive */
706 /* Try command line option path */
707 if (opt_sessiond_path != NULL) {
708 ret = access(opt_sessiond_path, F_OK | X_OK);
709 if (ret < 0) {
710 ERR("No such file: %s", opt_sessiond_path);
711 goto end;
712 }
713 pathname = opt_sessiond_path;
714 } else {
715 /* Try LTTNG_SESSIOND_PATH env variable */
716 pathname = getenv(LTTNG_SESSIOND_PATH_ENV);
717 }
718
719 /* Let's rock and roll */
720 if (pathname == NULL) {
721 ret = asprintf(&alloc_pathname, "ltt-sessiond");
722 if (ret < 0) {
723 goto end;
724 }
725 pathname = alloc_pathname;
726 }
727
728 ret = spawn_sessiond(pathname);
729 free(alloc_pathname);
730 if (ret < 0) {
731 ERR("Problem occurs when starting %s", pathname);
732 goto end;
733 }
734 }
735
736 end:
737 return ret;
738 }
739
740 /*
741 * set_signal_handler
742 *
743 * Setup signal handler for SIGCHLD and SIGTERM.
744 */
745 static int set_signal_handler(void)
746 {
747 int ret = 0;
748 struct sigaction sa;
749 sigset_t sigset;
750
751 if ((ret = sigemptyset(&sigset)) < 0) {
752 perror("sigemptyset");
753 goto end;
754 }
755
756 sa.sa_handler = sighandler;
757 sa.sa_mask = sigset;
758 sa.sa_flags = 0;
759 if ((ret = sigaction(SIGCHLD, &sa, NULL)) < 0) {
760 perror("sigaction");
761 goto end;
762 }
763
764 if ((ret = sigaction(SIGTERM, &sa, NULL)) < 0) {
765 perror("sigaction");
766 goto end;
767 }
768
769 end:
770 return ret;
771 }
772
773 /*
774 * sighandler
775 *
776 * Signal handler for the daemon
777 */
778 static void sighandler(int sig)
779 {
780 switch (sig) {
781 case SIGTERM:
782 DBG("SIGTERM catched");
783 clean_exit(EXIT_FAILURE);
784 break;
785 case SIGCHLD:
786 /* Notify is done */
787 DBG("SIGCHLD catched");
788 break;
789 default:
790 DBG("Unknown signal %d catched", sig);
791 break;
792 }
793
794 return;
795 }
796
797 /*
798 * clean_exit
799 */
800 void clean_exit(int code)
801 {
802 DBG("Clean exit");
803 if (session_name) {
804 free(session_name);
805 }
806
807 exit(code);
808 }
809
810 /*
811 * main
812 */
813 int main(int argc, char *argv[])
814 {
815 int ret;
816
817 progname = argv[0] ? argv[0] : "lttng";
818
819 /* For Mathieu Desnoyers aka Dr Tracing */
820 if (strncmp(progname, "drtrace", 7) == 0) {
821 MSG("%c[%d;%dmWelcome back Dr Tracing!%c[%dm\n\n", 27,1,33,27,0);
822 }
823
824 ret = parse_args(argc, (const char **) argv);
825 if (ret < 0) {
826 clean_exit(EXIT_FAILURE);
827 }
828
829 ret = validate_options();
830 if (ret < 0) {
831 return EXIT_FAILURE;
832 }
833
834 ret = set_signal_handler();
835 if (ret < 0) {
836 clean_exit(ret);
837 }
838
839 if (opt_tracing_group != NULL) {
840 DBG("Set tracing group to '%s'", opt_tracing_group);
841 lttng_set_tracing_group(opt_tracing_group);
842 }
843
844 /* If ask for kernel tracing, need root perms */
845 if (opt_trace_kernel) {
846 DBG("Kernel tracing activated");
847 if (getuid() != 0) {
848 ERR("%s must be setuid root", progname);
849 clean_exit(-EPERM);
850 }
851 }
852
853 /* Check if the lttng session daemon is running.
854 * If no, a daemon will be spawned.
855 */
856 if (opt_no_sessiond == 0 && (check_ltt_sessiond() < 0)) {
857 clean_exit(EXIT_FAILURE);
858 }
859
860 ret = process_client_opt();
861 if (ret < 0) {
862 clean_exit(ret);
863 }
864
865 clean_exit(0);
866
867 return 0;
868 }
This page took 0.043836 seconds and 3 git commands to generate.