Add parameters name to the function prototype
[lttng-tools.git] / lttng / lttng.c
CommitLineData
826d496d
MD
1/*
2 * Copyright (c) 2011 David Goulet <david.goulet@polymtl.ca>
fac6795d
DG
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.
fac6795d
DG
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
5b97ec60 33#include <lttng/lttng.h>
fac6795d
DG
34
35#include "lttng.h"
36#include "lttngerr.h"
37
38/* Variables */
39static char *progname;
96243366
DG
40static char *session_name;
41static char short_str_uuid[UUID_SHORT_STR_LEN];
42static char long_str_uuid[UUID_STR_LEN];
43static uuid_t current_uuid;
fac6795d
DG
44
45/* Prototypes */
46static int process_client_opt(void);
47static int process_opt_list_apps(void);
57167058 48static int process_opt_list_sessions(void);
1657e9bb 49static int process_opt_list_traces(void);
aaf97519 50static int process_opt_create_session(void);
96243366 51static int set_session_uuid(void);
5b8719f5
DG
52static void sighandler(int sig);
53static int set_signal_handler(void);
8548ff30 54static int validate_options(void);
47b74d63 55static char *get_cmdline_by_pid(pid_t pid);
96243366
DG
56static void set_opt_session_info(void);
57static void shorten_uuid(char *long_u, char *short_u);
fac6795d
DG
58
59/*
60 * start_client
61 *
62 * Process client request from the command line
63 * options. Every tracing action is done by the
64 * liblttngctl API.
65 */
66static int process_client_opt(void)
67{
68 int ret;
96243366
DG
69
70 set_opt_session_info();
fac6795d 71
fac6795d
DG
72 if (opt_list_apps) {
73 ret = process_opt_list_apps();
74 if (ret < 0) {
fac6795d
DG
75 goto end;
76 }
77 }
78
57167058
DG
79 if (opt_list_session) {
80 ret = process_opt_list_sessions();
81 if (ret < 0) {
82 goto end;
83 }
84 }
85
96243366
DG
86 if (opt_destroy_session) {
87 ret = lttng_destroy_session(&current_uuid);
1657e9bb
DG
88 if (ret < 0) {
89 goto end;
90 }
96243366 91 MSG("Session %s destroyed.", opt_session_uuid);
1657e9bb
DG
92 }
93
96243366
DG
94 if (!opt_list_session && !opt_list_apps) {
95 if (uuid_is_null(current_uuid)) {
96 /* If no session uuid, create session */
97 DBG("No session specified. Creating session.");
98 ret = process_opt_create_session();
99 if (ret < 0) {
100 goto end;
101 }
aaf97519 102 }
aaf97519 103
96243366
DG
104 DBG("Set session uuid to %s", long_str_uuid);
105 ret = set_session_uuid();
8028d920 106 if (ret < 0) {
96243366
DG
107 ERR("Session UUID %s not found", opt_session_uuid);
108 goto error;
8028d920
DG
109 }
110 }
111
96243366
DG
112 if (opt_list_traces) {
113 ret = process_opt_list_traces();
7442b2ba 114 if (ret < 0) {
96243366 115 goto end;
7442b2ba 116 }
e8be5f4f
DG
117 }
118
96243366
DG
119 /*
120 * Action on traces (kernel or/and userspace).
121 */
ad874cce
DG
122 if (opt_trace_kernel) {
123 ERR("Not implemented yet");
124 goto end;
df0da139
DG
125 }
126
ad874cce
DG
127 if (opt_trace_pid != 0) {
128 if (opt_create_trace) {
129 DBG("Create a userspace trace for pid %d", opt_trace_pid);
130 ret = lttng_ust_create_trace(opt_trace_pid);
131 if (ret < 0) {
132 goto end;
133 }
134 MSG("Trace created successfully!\nUse --start to start tracing.");
ce3d728c 135 }
ce3d728c 136
ad874cce
DG
137 if (opt_start_trace) {
138 DBG("Start trace for pid %d", opt_trace_pid);
139 ret = lttng_ust_start_trace(opt_trace_pid);
140 if (ret < 0) {
141 goto end;
142 }
143 MSG("Trace started successfully!");
144 } else if (opt_stop_trace) {
145 DBG("Stop trace for pid %d", opt_trace_pid);
146 ret = lttng_ust_stop_trace(opt_trace_pid);
147 if (ret < 0) {
148 goto end;
149 }
150 MSG("Trace stopped successfully!");
520ff687 151 }
ad874cce 152
520ff687
DG
153 }
154
fac6795d
DG
155 return 0;
156
157end:
ebafd2a5 158 ERR("%s", lttng_get_readable_code(ret));
fac6795d 159 return ret;
7442b2ba
DG
160
161error:
162 return ret;
163}
164
165/*
96243366
DG
166 * set_opt_session_info
167 *
168 * Setup session_name, current_uuid, short_str_uuid and
169 * long_str_uuid using the command line options.
170 */
171static void set_opt_session_info(void)
172{
173 int count, i, short_len;
174 char *tok;
175 struct lttng_session *sessions;
176
177 if (opt_session_uuid != NULL) {
178 short_len = sizeof(short_str_uuid) - 1;
179 /* Shorten uuid */
180 tok = strchr(opt_session_uuid, '.');
181 if (strlen(tok + 1) == short_len) {
182 memcpy(short_str_uuid, tok + 1, short_len);
183 short_str_uuid[short_len] = '\0';
184 }
185
186 /* Get long real uuid_t from session daemon */
187 count = lttng_list_sessions(&sessions);
188 for (i = 0; i < count; i++) {
189 uuid_unparse(sessions[i].uuid, long_str_uuid);
190 if (strncmp(long_str_uuid, short_str_uuid, 8) == 0) {
191 uuid_copy(current_uuid, sessions[i].uuid);
192 break;
193 }
194 }
195 }
196
197 if (opt_session_name != NULL) {
198 session_name = strndup(opt_session_name, NAME_MAX);
199 }
200}
201
202/*
203 * shorten_uuid
204 *
205 * Small function to shorten the 37 bytes long uuid_t
206 * string representation to 8 characters.
207 */
208static void shorten_uuid(char *long_u, char *short_u)
209{
210 memcpy(short_u, long_u, 8);
211 short_u[UUID_SHORT_STR_LEN - 1] = '\0';
212}
213
214/*
215 * set_session_uuid
7442b2ba
DG
216 *
217 * Set current session uuid to the current flow of
96243366
DG
218 * command(s) using the already shorten uuid or
219 * current full uuid.
7442b2ba 220 */
96243366 221static int set_session_uuid(void)
7442b2ba
DG
222{
223 int ret, count, i;
96243366 224 char str_uuid[37];
7442b2ba
DG
225 struct lttng_session *sessions;
226
96243366
DG
227 if (!uuid_is_null(current_uuid)) {
228 lttng_set_current_session_uuid(&current_uuid);
229 goto end;
230 }
231
7442b2ba
DG
232 count = lttng_list_sessions(&sessions);
233 if (count < 0) {
234 ret = count;
235 goto error;
236 }
237
238 for (i = 0; i < count; i++) {
96243366
DG
239 uuid_unparse(sessions[i].uuid, str_uuid);
240 if (strncmp(str_uuid, short_str_uuid, 8) == 0) {
241 lttng_set_current_session_uuid(&sessions[i].uuid);
7442b2ba
DG
242 break;
243 }
244 }
245
246 free(sessions);
247
96243366 248end:
7442b2ba
DG
249 return 0;
250
251error:
252 return ret;
fac6795d
DG
253}
254
1657e9bb
DG
255/*
256 * process_opt_list_traces
257 *
258 * Get list of all traces for a specific session uuid.
259 */
260static int process_opt_list_traces(void)
261{
262 int ret, i;
1657e9bb
DG
263 struct lttng_trace *traces;
264
96243366 265 ret = lttng_list_traces(&current_uuid, &traces);
1657e9bb
DG
266 if (ret < 0) {
267 goto error;
268 }
269
270 MSG("Userspace traces:");
271 for (i = 0; i < ret; i++) {
272 if (traces[i].type == USERSPACE) {
47b74d63
DG
273 MSG("\t%d) %s (pid: %d): %s",
274 i, traces[i].name, traces[i].pid,
275 get_cmdline_by_pid(traces[i].pid));
1657e9bb
DG
276 } else {
277 break;
278 }
279 }
280
281 MSG("Kernel traces:");
282 for (;i < ret; i++) {
283 if (traces[i].type == KERNEL) {
284 MSG("\t%d) %s", i, traces[i].name);
285 }
286 }
287
288 free(traces);
289
290error:
291 return ret;
292}
293
aaf97519
DG
294/*
295 * process_opt_create_session
296 *
297 * Create a new session using the name pass
298 * to the command line.
299 */
300static int process_opt_create_session(void)
301{
302 int ret;
8028d920
DG
303 uuid_t session_id;
304 char str_uuid[37];
96243366
DG
305 char name[NAME_MAX];
306 time_t rawtime;
307 struct tm *timeinfo;
308
309 /* Auto session creation */
310 if (opt_create_session == 0) {
311 time(&rawtime);
312 timeinfo = localtime(&rawtime);
313 strftime(name, sizeof(name), "%Y%m%d-%H%M%S", timeinfo);
314 session_name = strndup(name, sizeof(name));
315 }
aaf97519 316
96243366 317 ret = lttng_create_session(session_name, &session_id);
aaf97519
DG
318 if (ret < 0) {
319 goto error;
320 }
321
8028d920 322 uuid_unparse(session_id, str_uuid);
96243366
DG
323 uuid_copy(current_uuid, session_id);
324 shorten_uuid(str_uuid, short_str_uuid);
8028d920 325
96243366 326 MSG("Session UUID created: %s.%s", session_name, short_str_uuid);
aaf97519
DG
327
328error:
329 return ret;
330}
331
57167058
DG
332/*
333 * process_opt_list_sessions
334 *
335 * Get the list of available sessions from
336 * the session daemon and print it to user.
337 */
338static int process_opt_list_sessions(void)
339{
340 int ret, count, i;
7442b2ba 341 char tmp_short_uuid[9];
96243366 342 char str_uuid[37];
57167058
DG
343 struct lttng_session *sess;
344
345 count = lttng_list_sessions(&sess);
7442b2ba 346 DBG("Session count %d", count);
57167058
DG
347 if (count < 0) {
348 ret = count;
349 goto error;
350 }
351
7442b2ba 352 MSG("Available sessions (UUIDs):");
57167058 353 for (i = 0; i < count; i++) {
96243366
DG
354 uuid_unparse(sess[i].uuid, str_uuid);
355 shorten_uuid(str_uuid, tmp_short_uuid);
7442b2ba 356 MSG(" %d) %s.%s", i+1, sess[i].name, tmp_short_uuid);
57167058
DG
357 }
358
359 free(sess);
7442b2ba 360 MSG("\nTo select a session, use -s, --session UUID.");
57167058
DG
361
362 return 0;
363
364error:
365 return ret;
366}
367
fac6795d
DG
368/*
369 * process_opt_list_apps
370 *
371 * Get the UST traceable pid list and print
372 * them to the user.
373 */
374static int process_opt_list_apps(void)
375{
e8f07c63 376 int i, ret, count;
fac6795d 377 pid_t *pids;
1c9f7941 378 char *cmdline;
fac6795d 379
e8f07c63
DG
380 count = lttng_ust_list_apps(&pids);
381 if (count < 0) {
382 ret = count;
fac6795d
DG
383 goto error;
384 }
385
386 MSG("LTTng UST traceable application [name (pid)]:");
e8f07c63 387 for (i=0; i < count; i++) {
47b74d63
DG
388 cmdline = get_cmdline_by_pid(pids[i]);
389 if (cmdline == NULL) {
e8f07c63 390 MSG("\t(not running) (%d)", pids[i]);
fac6795d
DG
391 continue;
392 }
fac6795d 393 MSG("\t%s (%d)", cmdline, pids[i]);
1c9f7941 394 free(cmdline);
fac6795d
DG
395 }
396
e065084a
DG
397 /* Allocated by lttng_ust_list_apps() */
398 free(pids);
399
fac6795d
DG
400 return 0;
401
402error:
403 return ret;
404}
405
1c9f7941
DG
406/*
407 * get_cmdline_by_pid
408 *
47b74d63 409 * Get command line from /proc for a specific pid.
1c9f7941 410 *
47b74d63
DG
411 * On success, return an allocated string pointer pointing to
412 * the proc cmdline.
413 * On error, return NULL.
1c9f7941 414 */
47b74d63 415static char *get_cmdline_by_pid(pid_t pid)
1c9f7941
DG
416{
417 int ret;
418 FILE *fp;
47b74d63 419 char *cmdline = NULL;
1c9f7941
DG
420 char path[24]; /* Can't go bigger than /proc/65535/cmdline */
421
422 snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
423 fp = fopen(path, "r");
424 if (fp == NULL) {
47b74d63 425 goto end;
1c9f7941
DG
426 }
427
428 /* Caller must free() *cmdline */
47b74d63
DG
429 cmdline = malloc(PATH_MAX);
430 ret = fread(cmdline, 1, PATH_MAX, fp);
1c9f7941
DG
431 fclose(fp);
432
47b74d63
DG
433end:
434 return cmdline;
1c9f7941
DG
435}
436
8548ff30
DG
437/*
438 * validate_options
439 *
440 * Make sure that all options passed to the command line
441 * are compatible with each others.
442 *
443 * On error, return -1
444 * On success, return 0
445 */
446static int validate_options(void)
447{
ad874cce
DG
448 /* Conflicting command */
449 if (opt_start_trace && opt_stop_trace) {
450 ERR("Can't use --start and --stop together.");
451 goto error;
ad874cce
DG
452 /* If no PID specified and trace_kernel is off */
453 } else if ((opt_trace_pid == 0 && opt_trace_kernel == 0) &&
454 (opt_create_trace || opt_start_trace || opt_stop_trace)) {
455 ERR("Please specify a PID using -p, --pid PID.");
456 goto error;
96243366
DG
457 } else if (opt_session_uuid && opt_create_session) {
458 ERR("Please don't use -s and -c together. Useless action.");
459 goto error;
460 } else if (opt_list_traces && opt_session_uuid == NULL) {
461 ERR("Can't use -t without -s, --session option.");
462 goto error;
7442b2ba
DG
463 }
464
8548ff30
DG
465 return 0;
466
467error:
468 return -1;
469}
470
5b8719f5
DG
471/*
472 * spawn_sessiond
473 *
474 * Spawn a session daemon by forking and execv.
475 */
476static int spawn_sessiond(char *pathname)
477{
478 int ret = 0;
479 pid_t pid;
480
481 MSG("Spawning session daemon");
482 pid = fork();
483 if (pid == 0) {
484 /* Spawn session daemon and tell
485 * it to signal us when ready.
486 */
75462a81 487 ret = execlp(pathname, "ltt-sessiond", "--sig-parent", "--quiet", NULL);
5b8719f5
DG
488 if (ret < 0) {
489 if (errno == ENOENT) {
490 ERR("No session daemon found. Use --sessiond-path.");
491 } else {
492 perror("execlp");
493 }
494 kill(getppid(), SIGTERM);
495 exit(EXIT_FAILURE);
496 }
497 exit(EXIT_SUCCESS);
498 } else if (pid > 0) {
499 /* Wait for ltt-sessiond to start */
500 pause();
501 goto end;
502 } else {
503 perror("fork");
504 ret = -1;
505 goto end;
506 }
507
508end:
509 return ret;
510}
511
fac6795d
DG
512/*
513 * check_ltt_sessiond
514 *
515 * Check if the session daemon is available using
5b8719f5
DG
516 * the liblttngctl API for the check. If not, try to
517 * spawn a daemon.
fac6795d
DG
518 */
519static int check_ltt_sessiond(void)
520{
521 int ret;
5b8719f5 522 char *pathname = NULL;
fac6795d
DG
523
524 ret = lttng_check_session_daemon();
525 if (ret < 0) {
5b8719f5
DG
526 /* Try command line option path */
527 if (opt_sessiond_path != NULL) {
528 ret = access(opt_sessiond_path, F_OK | X_OK);
529 if (ret < 0) {
530 ERR("No such file: %s", opt_sessiond_path);
531 goto end;
532 }
533 pathname = opt_sessiond_path;
534 } else {
535 /* Try LTTNG_SESSIOND_PATH env variable */
e8f07c63
DG
536 pathname = getenv(LTTNG_SESSIOND_PATH_ENV);
537 if (pathname != NULL) {
538 /* strdup here in order to make the free()
539 * not fail later on.
540 */
541 pathname = strdup(pathname);
542 }
5b8719f5
DG
543 }
544
545 /* Let's rock and roll */
546 if (pathname == NULL) {
547 ret = asprintf(&pathname, "ltt-sessiond");
548 if (ret < 0) {
549 goto end;
550 }
551 }
552
553 ret = spawn_sessiond(pathname);
554 free(pathname);
555 if (ret < 0) {
556 ERR("Problem occurs when starting %s", pathname);
557 goto end;
558 }
fac6795d
DG
559 }
560
5b8719f5 561end:
fac6795d
DG
562 return ret;
563}
564
5b8719f5
DG
565/*
566 * set_signal_handler
567 *
568 * Setup signal handler for SIGCHLD and SIGTERM.
569 */
570static int set_signal_handler(void)
571{
572 int ret = 0;
573 struct sigaction sa;
574 sigset_t sigset;
575
576 if ((ret = sigemptyset(&sigset)) < 0) {
577 perror("sigemptyset");
578 goto end;
579 }
580
581 sa.sa_handler = sighandler;
582 sa.sa_mask = sigset;
583 sa.sa_flags = 0;
584 if ((ret = sigaction(SIGCHLD, &sa, NULL)) < 0) {
585 perror("sigaction");
586 goto end;
587 }
fac6795d 588
5b8719f5
DG
589 if ((ret = sigaction(SIGTERM, &sa, NULL)) < 0) {
590 perror("sigaction");
591 goto end;
592 }
593
594end:
595 return ret;
596}
597
598/*
599 * sighandler
600 *
601 * Signal handler for the daemon
602 */
603static void sighandler(int sig)
604{
5b8719f5
DG
605 switch (sig) {
606 case SIGTERM:
ce3d728c 607 DBG("SIGTERM catched");
5b8719f5
DG
608 clean_exit(EXIT_FAILURE);
609 break;
610 case SIGCHLD:
611 /* Notify is done */
ce3d728c 612 DBG("SIGCHLD catched");
5b8719f5
DG
613 break;
614 default:
ce3d728c 615 DBG("Unknown signal %d catched", sig);
5b8719f5
DG
616 break;
617 }
618
619 return;
620}
7442b2ba 621
fac6795d
DG
622/*
623 * clean_exit
624 */
625void clean_exit(int code)
626{
627 DBG("Clean exit");
96243366
DG
628 if (session_name) {
629 free(session_name);
630 }
631
fac6795d
DG
632 exit(code);
633}
634
635/*
5b8719f5 636 * main
fac6795d
DG
637 */
638int main(int argc, char *argv[])
639{
640 int ret;
641
642 progname = argv[0] ? argv[0] : "lttng";
643
644 /* For Mathieu Desnoyers aka Dr Tracing */
645 if (strncmp(progname, "drtrace", 7) == 0) {
646 MSG("%c[%d;%dmWelcome back Dr Tracing!%c[%dm\n\n", 27,1,33,27,0);
647 }
648
649 ret = parse_args(argc, (const char **) argv);
650 if (ret < 0) {
87378cf5 651 clean_exit(EXIT_FAILURE);
fac6795d
DG
652 }
653
8548ff30
DG
654 ret = validate_options();
655 if (ret < 0) {
656 return EXIT_FAILURE;
657 }
658
5b8719f5
DG
659 ret = set_signal_handler();
660 if (ret < 0) {
87378cf5 661 clean_exit(ret);
5b8719f5
DG
662 }
663
fac6795d
DG
664 if (opt_tracing_group != NULL) {
665 DBG("Set tracing group to '%s'", opt_tracing_group);
666 lttng_set_tracing_group(opt_tracing_group);
667 }
668
669 /* If ask for kernel tracing, need root perms */
670 if (opt_trace_kernel) {
671 DBG("Kernel tracing activated");
672 if (getuid() != 0) {
673 ERR("%s must be setuid root", progname);
87378cf5 674 clean_exit(-EPERM);
fac6795d
DG
675 }
676 }
677
678 /* Check if the lttng session daemon is running.
679 * If no, a daemon will be spawned.
680 */
5b8719f5 681 if (opt_no_sessiond == 0 && (check_ltt_sessiond() < 0)) {
87378cf5 682 clean_exit(EXIT_FAILURE);
fac6795d
DG
683 }
684
685 ret = process_client_opt();
686 if (ret < 0) {
87378cf5 687 clean_exit(ret);
fac6795d
DG
688 }
689
87378cf5
DG
690 clean_exit(0);
691
fac6795d
DG
692 return 0;
693}
This page took 0.055735 seconds and 5 git commands to generate.