Add trace listing feature
[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
33#include <lttng/liblttngctl.h>
34
35#include "lttng.h"
36#include "lttngerr.h"
37
38/* Variables */
39static char *progname;
40
41/* Prototypes */
42static int process_client_opt(void);
43static int process_opt_list_apps(void);
57167058 44static int process_opt_list_sessions(void);
1657e9bb 45static int process_opt_list_traces(void);
aaf97519 46static int process_opt_create_session(void);
5b8719f5
DG
47static void sighandler(int sig);
48static int set_signal_handler(void);
1c9f7941 49static int get_cmdline_by_pid(pid_t pid, char **cmdline);
8548ff30 50static int validate_options(void);
fac6795d
DG
51
52/*
53 * start_client
54 *
55 * Process client request from the command line
56 * options. Every tracing action is done by the
57 * liblttngctl API.
58 */
59static int process_client_opt(void)
60{
61 int ret;
8028d920 62 uuid_t uuid;
fac6795d
DG
63
64 /* Connect to the session daemon */
65 ret = lttng_connect_sessiond();
66 if (ret < 0) {
fac6795d
DG
67 goto end;
68 }
69
70 if (opt_list_apps) {
71 ret = process_opt_list_apps();
72 if (ret < 0) {
fac6795d
DG
73 goto end;
74 }
75 }
76
57167058
DG
77 if (opt_list_session) {
78 ret = process_opt_list_sessions();
79 if (ret < 0) {
80 goto end;
81 }
82 }
83
1657e9bb
DG
84 if (opt_list_traces) {
85 ret = process_opt_list_traces();
86 if (ret < 0) {
87 goto end;
88 }
89 }
90
aaf97519
DG
91 if (opt_create_session != NULL) {
92 ret = process_opt_create_session();
93 if (ret < 0) {
94 goto end;
95 }
96 }
97
8028d920
DG
98 if (opt_destroy_session != NULL) {
99 uuid_parse(opt_destroy_session, uuid);
100 ret = lttng_destroy_session(&uuid);
101 if (ret < 0) {
102 goto end;
103 }
104 }
105
e8be5f4f 106 if (opt_session_uuid != NULL) {
ce3d728c 107 DBG("Set session uuid to %s", opt_session_uuid);
e8be5f4f
DG
108 lttng_set_current_session_uuid(opt_session_uuid);
109 }
110
df0da139
DG
111 if (opt_create_trace) {
112 DBG("Create trace for pid %d", opt_create_trace);
113 ret = lttng_ust_create_trace(opt_create_trace);
114 if (ret < 0) {
115 goto end;
116 }
8548ff30 117 MSG("Trace created successfully!\nUse --start PID to start tracing.");
df0da139
DG
118 }
119
ce3d728c
DG
120 if (opt_start_trace) {
121 DBG("Start trace for pid %d", opt_start_trace);
122 ret = lttng_ust_start_trace(opt_start_trace);
123 if (ret < 0) {
124 goto end;
125 }
126 MSG("Trace started successfully!");
127 }
128
fac6795d
DG
129 return 0;
130
131end:
ebafd2a5 132 ERR("%s", lttng_get_readable_code(ret));
fac6795d
DG
133 return ret;
134}
135
1657e9bb
DG
136/*
137 * process_opt_list_traces
138 *
139 * Get list of all traces for a specific session uuid.
140 */
141static int process_opt_list_traces(void)
142{
143 int ret, i;
144 uuid_t uuid;
145 struct lttng_trace *traces;
146
147 uuid_parse(opt_session_uuid, uuid);
148 ret = lttng_list_traces(&uuid, &traces);
149 if (ret < 0) {
150 goto error;
151 }
152
153 MSG("Userspace traces:");
154 for (i = 0; i < ret; i++) {
155 if (traces[i].type == USERSPACE) {
156 MSG("\t%d) %s (pid: %d)", i, traces[i].name, traces[i].pid);
157 } else {
158 break;
159 }
160 }
161
162 MSG("Kernel traces:");
163 for (;i < ret; i++) {
164 if (traces[i].type == KERNEL) {
165 MSG("\t%d) %s", i, traces[i].name);
166 }
167 }
168
169 free(traces);
170
171error:
172 return ret;
173}
174
aaf97519
DG
175/*
176 * process_opt_create_session
177 *
178 * Create a new session using the name pass
179 * to the command line.
180 */
181static int process_opt_create_session(void)
182{
183 int ret;
8028d920
DG
184 uuid_t session_id;
185 char str_uuid[37];
aaf97519
DG
186
187 ret = lttng_create_session(opt_create_session, &session_id);
188 if (ret < 0) {
189 goto error;
190 }
191
8028d920
DG
192 uuid_unparse(session_id, str_uuid);
193
aaf97519 194 MSG("Session created:");
8028d920 195 MSG(" %s (%s)", opt_create_session, str_uuid);
aaf97519
DG
196
197error:
198 return ret;
199}
200
57167058
DG
201/*
202 * process_opt_list_sessions
203 *
204 * Get the list of available sessions from
205 * the session daemon and print it to user.
206 */
207static int process_opt_list_sessions(void)
208{
209 int ret, count, i;
210 struct lttng_session *sess;
211
212 count = lttng_list_sessions(&sess);
213 if (count < 0) {
214 ret = count;
215 goto error;
216 }
217
218 MSG("Available sessions [Name (uuid)]:");
219 for (i = 0; i < count; i++) {
220 MSG("\tName: %s (uuid: %s)", sess[i].name, sess[i].uuid);
221 }
222
223 free(sess);
224 MSG("\nTo select a session, use --session UUID.");
225
226 return 0;
227
228error:
229 return ret;
230}
231
fac6795d
DG
232/*
233 * process_opt_list_apps
234 *
235 * Get the UST traceable pid list and print
236 * them to the user.
237 */
238static int process_opt_list_apps(void)
239{
e8f07c63 240 int i, ret, count;
fac6795d 241 pid_t *pids;
1c9f7941 242 char *cmdline;
fac6795d 243
e8f07c63
DG
244 count = lttng_ust_list_apps(&pids);
245 if (count < 0) {
246 ret = count;
fac6795d
DG
247 goto error;
248 }
249
250 MSG("LTTng UST traceable application [name (pid)]:");
e8f07c63 251 for (i=0; i < count; i++) {
1c9f7941
DG
252 ret = get_cmdline_by_pid(pids[i], &cmdline);
253 if (!ret) {
e8f07c63 254 MSG("\t(not running) (%d)", pids[i]);
fac6795d
DG
255 continue;
256 }
fac6795d 257 MSG("\t%s (%d)", cmdline, pids[i]);
1c9f7941 258 free(cmdline);
fac6795d
DG
259 }
260
e065084a
DG
261 /* Allocated by lttng_ust_list_apps() */
262 free(pids);
263
fac6795d
DG
264 return 0;
265
266error:
267 return ret;
268}
269
1c9f7941
DG
270/*
271 * get_cmdline_by_pid
272 *
273 * Get command line from /proc for a
274 * specific pid. Allocate cmdline so the
275 * user must free() that pointer.
276 *
277 * On success, return 1
278 * On error (not found), return 0
279 */
280static int get_cmdline_by_pid(pid_t pid, char **cmdline)
281{
282 int ret;
283 FILE *fp;
284 char path[24]; /* Can't go bigger than /proc/65535/cmdline */
285
286 snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
287 fp = fopen(path, "r");
288 if (fp == NULL) {
289 goto not_running;
290 }
291
292 /* Caller must free() *cmdline */
293 *cmdline = malloc(PATH_MAX);
294 ret = fread(*cmdline, 1, PATH_MAX, fp);
295 fclose(fp);
296
297 return 1;
298
299not_running:
300 return 0;
301}
302
8548ff30
DG
303/*
304 * validate_options
305 *
306 * Make sure that all options passed to the command line
307 * are compatible with each others.
308 *
309 * On error, return -1
310 * On success, return 0
311 */
312static int validate_options(void)
313{
314 if ((opt_session_uuid == NULL) &&
1657e9bb
DG
315 (opt_create_trace || opt_start_trace || opt_list_traces)) {
316 ERR("You need to specify a session UUID.\nPlease use --session UUID to do so.");
8548ff30
DG
317 goto error;
318 }
319
320 return 0;
321
322error:
323 return -1;
324}
325
5b8719f5
DG
326/*
327 * spawn_sessiond
328 *
329 * Spawn a session daemon by forking and execv.
330 */
331static int spawn_sessiond(char *pathname)
332{
333 int ret = 0;
334 pid_t pid;
335
336 MSG("Spawning session daemon");
337 pid = fork();
338 if (pid == 0) {
339 /* Spawn session daemon and tell
340 * it to signal us when ready.
341 */
75462a81 342 ret = execlp(pathname, "ltt-sessiond", "--sig-parent", "--quiet", NULL);
5b8719f5
DG
343 if (ret < 0) {
344 if (errno == ENOENT) {
345 ERR("No session daemon found. Use --sessiond-path.");
346 } else {
347 perror("execlp");
348 }
349 kill(getppid(), SIGTERM);
350 exit(EXIT_FAILURE);
351 }
352 exit(EXIT_SUCCESS);
353 } else if (pid > 0) {
354 /* Wait for ltt-sessiond to start */
355 pause();
356 goto end;
357 } else {
358 perror("fork");
359 ret = -1;
360 goto end;
361 }
362
363end:
364 return ret;
365}
366
fac6795d
DG
367/*
368 * check_ltt_sessiond
369 *
370 * Check if the session daemon is available using
5b8719f5
DG
371 * the liblttngctl API for the check. If not, try to
372 * spawn a daemon.
fac6795d
DG
373 */
374static int check_ltt_sessiond(void)
375{
376 int ret;
5b8719f5 377 char *pathname = NULL;
fac6795d
DG
378
379 ret = lttng_check_session_daemon();
380 if (ret < 0) {
5b8719f5
DG
381 /* Try command line option path */
382 if (opt_sessiond_path != NULL) {
383 ret = access(opt_sessiond_path, F_OK | X_OK);
384 if (ret < 0) {
385 ERR("No such file: %s", opt_sessiond_path);
386 goto end;
387 }
388 pathname = opt_sessiond_path;
389 } else {
390 /* Try LTTNG_SESSIOND_PATH env variable */
e8f07c63
DG
391 pathname = getenv(LTTNG_SESSIOND_PATH_ENV);
392 if (pathname != NULL) {
393 /* strdup here in order to make the free()
394 * not fail later on.
395 */
396 pathname = strdup(pathname);
397 }
5b8719f5
DG
398 }
399
400 /* Let's rock and roll */
401 if (pathname == NULL) {
402 ret = asprintf(&pathname, "ltt-sessiond");
403 if (ret < 0) {
404 goto end;
405 }
406 }
407
408 ret = spawn_sessiond(pathname);
409 free(pathname);
410 if (ret < 0) {
411 ERR("Problem occurs when starting %s", pathname);
412 goto end;
413 }
fac6795d
DG
414 }
415
5b8719f5 416end:
fac6795d
DG
417 return ret;
418}
419
5b8719f5
DG
420/*
421 * set_signal_handler
422 *
423 * Setup signal handler for SIGCHLD and SIGTERM.
424 */
425static int set_signal_handler(void)
426{
427 int ret = 0;
428 struct sigaction sa;
429 sigset_t sigset;
430
431 if ((ret = sigemptyset(&sigset)) < 0) {
432 perror("sigemptyset");
433 goto end;
434 }
435
436 sa.sa_handler = sighandler;
437 sa.sa_mask = sigset;
438 sa.sa_flags = 0;
439 if ((ret = sigaction(SIGCHLD, &sa, NULL)) < 0) {
440 perror("sigaction");
441 goto end;
442 }
fac6795d 443
5b8719f5
DG
444 if ((ret = sigaction(SIGTERM, &sa, NULL)) < 0) {
445 perror("sigaction");
446 goto end;
447 }
448
449end:
450 return ret;
451}
452
453/*
454 * sighandler
455 *
456 * Signal handler for the daemon
457 */
458static void sighandler(int sig)
459{
5b8719f5
DG
460 switch (sig) {
461 case SIGTERM:
ce3d728c 462 DBG("SIGTERM catched");
5b8719f5
DG
463 clean_exit(EXIT_FAILURE);
464 break;
465 case SIGCHLD:
466 /* Notify is done */
ce3d728c 467 DBG("SIGCHLD catched");
5b8719f5
DG
468 break;
469 default:
ce3d728c 470 DBG("Unknown signal %d catched", sig);
5b8719f5
DG
471 break;
472 }
473
474 return;
475}
fac6795d
DG
476/*
477 * clean_exit
478 */
479void clean_exit(int code)
480{
481 DBG("Clean exit");
87378cf5
DG
482 if (lttng_disconnect_sessiond() < 0) {
483 ERR("Session daemon disconnect failed.");
484 }
fac6795d
DG
485 exit(code);
486}
487
488/*
5b8719f5 489 * main
fac6795d
DG
490 */
491int main(int argc, char *argv[])
492{
493 int ret;
494
495 progname = argv[0] ? argv[0] : "lttng";
496
497 /* For Mathieu Desnoyers aka Dr Tracing */
498 if (strncmp(progname, "drtrace", 7) == 0) {
499 MSG("%c[%d;%dmWelcome back Dr Tracing!%c[%dm\n\n", 27,1,33,27,0);
500 }
501
502 ret = parse_args(argc, (const char **) argv);
503 if (ret < 0) {
87378cf5 504 clean_exit(EXIT_FAILURE);
fac6795d
DG
505 }
506
8548ff30
DG
507 ret = validate_options();
508 if (ret < 0) {
509 return EXIT_FAILURE;
510 }
511
5b8719f5
DG
512 ret = set_signal_handler();
513 if (ret < 0) {
87378cf5 514 clean_exit(ret);
5b8719f5
DG
515 }
516
fac6795d
DG
517 if (opt_tracing_group != NULL) {
518 DBG("Set tracing group to '%s'", opt_tracing_group);
519 lttng_set_tracing_group(opt_tracing_group);
520 }
521
522 /* If ask for kernel tracing, need root perms */
523 if (opt_trace_kernel) {
524 DBG("Kernel tracing activated");
525 if (getuid() != 0) {
526 ERR("%s must be setuid root", progname);
87378cf5 527 clean_exit(-EPERM);
fac6795d
DG
528 }
529 }
530
531 /* Check if the lttng session daemon is running.
532 * If no, a daemon will be spawned.
533 */
5b8719f5 534 if (opt_no_sessiond == 0 && (check_ltt_sessiond() < 0)) {
87378cf5 535 clean_exit(EXIT_FAILURE);
fac6795d
DG
536 }
537
538 ret = process_client_opt();
539 if (ret < 0) {
87378cf5 540 clean_exit(ret);
fac6795d
DG
541 }
542
87378cf5
DG
543 clean_exit(0);
544
fac6795d
DG
545 return 0;
546}
This page took 0.044657 seconds and 4 git commands to generate.