Cleanup: Replace all perror() uses by the PERROR macro
[lttng-tools.git] / src / bin / 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, version 2 only,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18 #define _GNU_SOURCE
19 #define _LGPL_SOURCE
20 #include <getopt.h>
21 #include <signal.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/types.h>
26 #include <sys/wait.h>
27 #include <unistd.h>
28 #include <config.h>
29 #include <ctype.h>
30
31 #include <lttng/lttng.h>
32 #include <common/error.h>
33
34 #include "command.h"
35
36 /* Variables */
37 static char *progname;
38 static int opt_no_sessiond;
39 static char *opt_sessiond_path;
40 static pid_t sessiond_pid;
41 static volatile int recv_child_signal;
42
43 char *opt_relayd_path;
44
45 enum {
46 OPT_RELAYD_PATH,
47 OPT_SESSION_PATH,
48 OPT_DUMP_OPTIONS,
49 OPT_DUMP_COMMANDS,
50 };
51
52 /* Getopt options. No first level command. */
53 static struct option long_options[] = {
54 {"version", 0, NULL, 'V'},
55 {"help", 0, NULL, 'h'},
56 {"group", 1, NULL, 'g'},
57 {"verbose", 0, NULL, 'v'},
58 {"quiet", 0, NULL, 'q'},
59 {"mi", 1, NULL, 'm'},
60 {"no-sessiond", 0, NULL, 'n'},
61 {"sessiond-path", 1, NULL, OPT_SESSION_PATH},
62 {"relayd-path", 1, NULL, OPT_RELAYD_PATH},
63 {"list-options", 0, NULL, OPT_DUMP_OPTIONS},
64 {"list-commands", 0, NULL, OPT_DUMP_COMMANDS},
65 {NULL, 0, NULL, 0}
66 };
67
68 /* First level command */
69 static struct cmd_struct commands[] = {
70 { "list", cmd_list},
71 { "create", cmd_create},
72 { "destroy", cmd_destroy},
73 { "start", cmd_start},
74 { "stop", cmd_stop},
75 { "enable-event", cmd_enable_events},
76 { "disable-event", cmd_disable_events},
77 { "enable-channel", cmd_enable_channels},
78 { "disable-channel", cmd_disable_channels},
79 { "add-context", cmd_add_context},
80 { "set-session", cmd_set_session},
81 { "version", cmd_version},
82 { "calibrate", cmd_calibrate},
83 { "view", cmd_view},
84 { "snapshot", cmd_snapshot},
85 { "save", cmd_save},
86 { "load", cmd_load},
87 { NULL, NULL} /* Array closure */
88 };
89
90 static void usage(FILE *ofp)
91 {
92 fprintf(ofp, "LTTng Trace Control " VERSION " - " VERSION_NAME "%s\n\n",
93 GIT_VERSION[0] == '\0' ? "" : " - " GIT_VERSION);
94 fprintf(ofp, "usage: lttng [OPTIONS] <COMMAND> [<ARGS>]\n");
95 fprintf(ofp, "\n");
96 fprintf(ofp, "Options:\n");
97 fprintf(ofp, " -V, --version Show version\n");
98 fprintf(ofp, " -h, --help Show this help\n");
99 fprintf(ofp, " --list-options Simple listing of lttng options\n");
100 fprintf(ofp, " --list-commands Simple listing of lttng commands\n");
101 fprintf(ofp, " -v, --verbose Increase verbosity\n");
102 fprintf(ofp, " -q, --quiet Quiet mode\n");
103 fprintf(ofp, " -m, --mi TYPE Machine Interface mode.\n");
104 fprintf(ofp, " Type: xml\n");
105 fprintf(ofp, " -g, --group NAME Unix tracing group name. (default: tracing)\n");
106 fprintf(ofp, " -n, --no-sessiond Don't spawn a session daemon\n");
107 fprintf(ofp, " --sessiond-path PATH Session daemon full path\n");
108 fprintf(ofp, " --relayd-path PATH Relayd daemon full path\n");
109 fprintf(ofp, "\n");
110 fprintf(ofp, "Commands:\n");
111 fprintf(ofp, " add-context Add context to event and/or channel\n");
112 fprintf(ofp, " calibrate Quantify LTTng overhead\n");
113 fprintf(ofp, " create Create tracing session\n");
114 fprintf(ofp, " destroy Tear down tracing session\n");
115 fprintf(ofp, " enable-channel Enable tracing channel\n");
116 fprintf(ofp, " enable-event Enable tracing event\n");
117 fprintf(ofp, " disable-channel Disable tracing channel\n");
118 fprintf(ofp, " disable-event Disable tracing event\n");
119 fprintf(ofp, " list List possible tracing options\n");
120 fprintf(ofp, " set-session Set current session name\n");
121 fprintf(ofp, " snapshot Snapshot buffers of current session name\n");
122 fprintf(ofp, " start Start tracing\n");
123 fprintf(ofp, " stop Stop tracing\n");
124 fprintf(ofp, " version Show version information\n");
125 fprintf(ofp, " view Start trace viewer\n");
126 fprintf(ofp, " save Save session configuration\n");
127 fprintf(ofp, " load Load session configuration\n");
128 fprintf(ofp, "\n");
129 fprintf(ofp, "Each command also has its own -h, --help option.\n");
130 fprintf(ofp, "\n");
131 fprintf(ofp, "Please see the lttng(1) man page for full documentation.\n");
132 fprintf(ofp, "See http://lttng.org for updates, bug reports and news.\n");
133 }
134
135 static void version(FILE *ofp)
136 {
137 fprintf(ofp, "%s (LTTng Trace Control) " VERSION" - " VERSION_NAME "%s\n",
138 progname,
139 GIT_VERSION[0] == '\0' ? "" : " - " GIT_VERSION);
140 }
141
142 /*
143 * Find the MI output type enum from a string. This function is for the support
144 * of machine interface output.
145 */
146 static int mi_output_type(const char *output_type)
147 {
148 int ret = 0;
149
150 if (!strncasecmp("xml", output_type, 3)) {
151 ret = LTTNG_MI_XML;
152 } else {
153 /* Invalid output format */
154 ERR("MI output format not supported");
155 ret = -LTTNG_ERR_MI_OUTPUT_TYPE;
156 }
157
158 return ret;
159 }
160
161 /*
162 * list_options
163 *
164 * List options line by line. This is mostly for bash auto completion and to
165 * avoid difficult parsing.
166 */
167 static void list_options(FILE *ofp)
168 {
169 int i = 0;
170 struct option *option = NULL;
171
172 option = &long_options[i];
173 while (option->name != NULL) {
174 fprintf(ofp, "--%s\n", option->name);
175
176 if (isprint(option->val)) {
177 fprintf(ofp, "-%c\n", option->val);
178 }
179
180 i++;
181 option = &long_options[i];
182 }
183 }
184
185 /*
186 * clean_exit
187 */
188 static void clean_exit(int code)
189 {
190 DBG("Clean exit");
191 exit(code);
192 }
193
194 /*
195 * sighandler
196 *
197 * Signal handler for the daemon
198 */
199 static void sighandler(int sig)
200 {
201 int status;
202
203 switch (sig) {
204 case SIGTERM:
205 DBG("SIGTERM caught");
206 clean_exit(EXIT_FAILURE);
207 break;
208 case SIGCHLD:
209 DBG("SIGCHLD caught");
210 waitpid(sessiond_pid, &status, 0);
211 recv_child_signal = 1;
212 /* Indicate that the session daemon died */
213 sessiond_pid = 0;
214 ERR("Session daemon died (exit status %d)", WEXITSTATUS(status));
215 break;
216 case SIGUSR1:
217 /* Notify is done */
218 recv_child_signal = 1;
219 DBG("SIGUSR1 caught");
220 break;
221 default:
222 DBG("Unknown signal %d caught", sig);
223 break;
224 }
225
226 return;
227 }
228
229 /*
230 * set_signal_handler
231 *
232 * Setup signal handler for SIGCHLD and SIGTERM.
233 */
234 static int set_signal_handler(void)
235 {
236 int ret = 0;
237 struct sigaction sa;
238 sigset_t sigset;
239
240 if ((ret = sigemptyset(&sigset)) < 0) {
241 PERROR("sigemptyset");
242 goto end;
243 }
244
245 sa.sa_handler = sighandler;
246 sa.sa_mask = sigset;
247 sa.sa_flags = 0;
248 if ((ret = sigaction(SIGUSR1, &sa, NULL)) < 0) {
249 PERROR("sigaction");
250 goto end;
251 }
252
253 if ((ret = sigaction(SIGTERM, &sa, NULL)) < 0) {
254 PERROR("sigaction");
255 goto end;
256 }
257
258 if ((ret = sigaction(SIGCHLD, &sa, NULL)) < 0) {
259 PERROR("sigaction");
260 goto end;
261 }
262
263 end:
264 return ret;
265 }
266
267 /*
268 * handle_command
269 *
270 * Handle the full argv list of a first level command. Will find the command
271 * in the global commands array and call the function callback associated.
272 *
273 * If command not found, return -1
274 * else, return function command error code.
275 */
276 static int handle_command(int argc, char **argv)
277 {
278 int i = 0, ret;
279 struct cmd_struct *cmd;
280
281 if (*argv == NULL) {
282 ret = CMD_SUCCESS;
283 goto end;
284 }
285
286 cmd = &commands[i];
287 while (cmd->func != NULL) {
288 /* Find command */
289 if (strcmp(argv[0], cmd->name) == 0) {
290 ret = cmd->func(argc, (const char**) argv);
291 goto end;
292 }
293 i++;
294 cmd = &commands[i];
295 }
296
297 /* Command not found */
298 ret = CMD_UNDEFINED;
299
300 end:
301 return ret;
302 }
303
304 /*
305 * spawn_sessiond
306 *
307 * Spawn a session daemon by forking and execv.
308 */
309 static int spawn_sessiond(char *pathname)
310 {
311 int ret = 0;
312 pid_t pid;
313
314 MSG("Spawning a session daemon");
315 recv_child_signal = 0;
316 pid = fork();
317 if (pid == 0) {
318 /*
319 * Spawn session daemon and tell
320 * it to signal us when ready.
321 */
322 execlp(pathname, "lttng-sessiond", "--sig-parent", "--quiet", NULL);
323 /* execlp only returns if error happened */
324 if (errno == ENOENT) {
325 ERR("No session daemon found. Use --sessiond-path.");
326 } else {
327 PERROR("execlp");
328 }
329 kill(getppid(), SIGTERM); /* wake parent */
330 exit(EXIT_FAILURE);
331 } else if (pid > 0) {
332 sessiond_pid = pid;
333 /*
334 * Wait for lttng-sessiond to start. We need to use a flag to check if
335 * the signal has been sent to us, because the child can be scheduled
336 * before the parent, and thus send the signal before this check. In
337 * the signal handler, we set the recv_child_signal flag, so anytime we
338 * check it after the fork is fine. Note that sleep() is interrupted
339 * before the 1 second delay as soon as the signal is received, so it
340 * will not cause visible delay for the user.
341 */
342 while (!recv_child_signal) {
343 sleep(1);
344 }
345 /*
346 * The signal handler will nullify sessiond_pid on SIGCHLD
347 */
348 if (!sessiond_pid) {
349 exit(EXIT_FAILURE);
350 }
351 goto end;
352 } else {
353 PERROR("fork");
354 ret = -1;
355 goto end;
356 }
357
358 end:
359 return ret;
360 }
361
362 /*
363 * check_sessiond
364 *
365 * Check if the session daemon is available using
366 * the liblttngctl API for the check. If not, try to
367 * spawn a daemon.
368 */
369 static int check_sessiond(void)
370 {
371 int ret;
372 char *pathname = NULL;
373
374 ret = lttng_session_daemon_alive();
375 if (ret == 0) { /* not alive */
376 /* Try command line option path */
377 pathname = opt_sessiond_path;
378
379 /* Try LTTNG_SESSIOND_PATH env variable */
380 if (pathname == NULL) {
381 pathname = getenv(DEFAULT_SESSIOND_PATH_ENV);
382 }
383
384 /* Try with configured path */
385 if (pathname == NULL) {
386 if (CONFIG_SESSIOND_BIN[0] != '\0') {
387 pathname = CONFIG_SESSIOND_BIN;
388 }
389 }
390
391 /* Let's rock and roll while trying the default path */
392 if (pathname == NULL) {
393 pathname = INSTALL_BIN_PATH "/lttng-sessiond";
394 }
395
396 DBG("Session daemon at: %s", pathname);
397
398 /* Check existence and permissions */
399 ret = access(pathname, F_OK | X_OK);
400 if (ret < 0) {
401 ERR("No such file or access denied: %s", pathname);
402 goto end;
403 }
404
405 ret = spawn_sessiond(pathname);
406 if (ret < 0) {
407 ERR("Problem occurred when starting %s", pathname);
408 }
409 }
410 end:
411 return ret;
412 }
413
414 /*
415 * Check args for specific options that *must* not trigger a session daemon
416 * execution.
417 *
418 * Return 1 if match else 0.
419 */
420 static int check_args_no_sessiond(int argc, char **argv)
421 {
422 int i;
423
424 for (i = 0; i < argc; i++) {
425 if ((strncmp(argv[i], "-h", sizeof("-h")) == 0) ||
426 strncmp(argv[i], "--h", sizeof("--h")) == 0 ||
427 strncmp(argv[i], "--list-options", sizeof("--list-options")) == 0 ||
428 strncmp(argv[i], "--list-commands", sizeof("--list-commands")) == 0 ||
429 strncmp(argv[i], "version", sizeof("version")) == 0 ||
430 strncmp(argv[i], "view", sizeof("view")) == 0) {
431 return 1;
432 }
433 }
434
435 return 0;
436 }
437
438 /*
439 * Parse command line arguments.
440 *
441 * Return 0 if OK, else -1
442 */
443 static int parse_args(int argc, char **argv)
444 {
445 int opt, ret;
446 char *user;
447
448 if (argc < 2) {
449 usage(stderr);
450 clean_exit(EXIT_FAILURE);
451 }
452
453 while ((opt = getopt_long(argc, argv, "+Vhnvqg:m:", long_options, NULL)) != -1) {
454 switch (opt) {
455 case 'V':
456 version(stdout);
457 ret = 0;
458 goto end;
459 case 'h':
460 usage(stdout);
461 ret = 0;
462 goto end;
463 case 'v':
464 /* There is only 3 possible level of verbosity. (-vvv) */
465 if (lttng_opt_verbose < 3) {
466 lttng_opt_verbose += 1;
467 }
468 break;
469 case 'q':
470 lttng_opt_quiet = 1;
471 break;
472 case 'm':
473 lttng_opt_mi = mi_output_type(optarg);
474 if (lttng_opt_mi < 0) {
475 ret = lttng_opt_mi;
476 goto error;
477 }
478 break;
479 case 'g':
480 lttng_set_tracing_group(optarg);
481 break;
482 case 'n':
483 opt_no_sessiond = 1;
484 break;
485 case OPT_SESSION_PATH:
486 opt_sessiond_path = strdup(optarg);
487 if (!opt_sessiond_path) {
488 ret = -1;
489 goto error;
490 }
491 break;
492 case OPT_RELAYD_PATH:
493 opt_relayd_path = strdup(optarg);
494 if (!opt_relayd_path) {
495 ret = -1;
496 goto error;
497 }
498 break;
499 case OPT_DUMP_OPTIONS:
500 list_options(stdout);
501 ret = 0;
502 goto end;
503 case OPT_DUMP_COMMANDS:
504 list_commands(commands, stdout);
505 ret = 0;
506 goto end;
507 default:
508 usage(stderr);
509 ret = 1;
510 goto error;
511 }
512 }
513
514 /* If both options are specified, quiet wins */
515 if (lttng_opt_verbose && lttng_opt_quiet) {
516 lttng_opt_verbose = 0;
517 }
518
519 /* Spawn session daemon if needed */
520 if (opt_no_sessiond == 0 && check_args_no_sessiond(argc, argv) == 0 &&
521 (check_sessiond() < 0)) {
522 ret = 1;
523 goto error;
524 }
525
526 /* No leftovers, print usage and quit */
527 if ((argc - optind) == 0) {
528 usage(stderr);
529 ret = 1;
530 goto error;
531 }
532
533 /* For Mathieu Desnoyers a.k.a. Dr. Tracing */
534 user = getenv("USER");
535 if (user != NULL && ((strncmp(progname, "drtrace", 7) == 0 ||
536 strncmp("compudj", user, 7) == 0))) {
537 MSG("%c[%d;%dmWelcome back Dr Tracing!%c[%dm\n", 27,1,33,27,0);
538 }
539 /* Thanks Mathieu */
540
541 /*
542 * Handle leftovers which is a first level command with the trailing
543 * options.
544 */
545 ret = handle_command(argc - optind, argv + optind);
546 switch (ret) {
547 case CMD_WARNING:
548 WARN("Some command(s) went wrong");
549 break;
550 case CMD_ERROR:
551 ERR("Command error");
552 break;
553 case CMD_UNDEFINED:
554 ERR("Undefined command");
555 break;
556 case CMD_FATAL:
557 ERR("Fatal error");
558 break;
559 case CMD_UNSUPPORTED:
560 ERR("Unsupported command");
561 break;
562 case -1:
563 usage(stderr);
564 ret = 1;
565 break;
566 case 0:
567 break;
568 default:
569 if (ret < 0) {
570 ret = -ret;
571 }
572 break;
573 }
574
575 end:
576 error:
577 return ret;
578 }
579
580
581 /*
582 * main
583 */
584 int main(int argc, char *argv[])
585 {
586 int ret;
587
588 progname = argv[0] ? argv[0] : "lttng";
589
590 ret = set_signal_handler();
591 if (ret < 0) {
592 clean_exit(ret);
593 }
594
595 ret = parse_args(argc, argv);
596 if (ret != 0) {
597 clean_exit(ret);
598 }
599
600 return 0;
601 }
This page took 0.042239 seconds and 5 git commands to generate.