+++ /dev/null
-/*
- * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <getopt.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <ctype.h>
-
-#include <lttng/lttng.h>
-#include <common/error.h>
-#include <common/compat/getenv.h>
-#include <common/utils.h>
-
-#include "command.h"
-#include "version.h"
-
-static const char *help_msg =
-#ifdef LTTNG_EMBED_HELP
-#include <lttng.1.h>
-#else
-NULL
-#endif
-;
-
-/* Variables */
-static const char *progname;
-int opt_no_sessiond;
-char *opt_sessiond_path;
-
-char *opt_relayd_path;
-
-enum {
- OPT_RELAYD_PATH,
- OPT_SESSION_PATH,
- OPT_DUMP_OPTIONS,
- OPT_DUMP_COMMANDS,
-};
-
-/* Getopt options. No first level command. */
-static struct option long_options[] = {
- {"version", 0, NULL, 'V'},
- {"help", 0, NULL, 'h'},
- {"group", 1, NULL, 'g'},
- {"verbose", 0, NULL, 'v'},
- {"quiet", 0, NULL, 'q'},
- {"mi", 1, NULL, 'm'},
- {"no-sessiond", 0, NULL, 'n'},
- {"sessiond-path", 1, NULL, OPT_SESSION_PATH},
- {"relayd-path", 1, NULL, OPT_RELAYD_PATH},
- {"list-options", 0, NULL, OPT_DUMP_OPTIONS},
- {"list-commands", 0, NULL, OPT_DUMP_COMMANDS},
- {NULL, 0, NULL, 0}
-};
-
-/* First level command */
-static struct cmd_struct commands[] = {
- { "add-context", cmd_add_context},
- { "add-trigger", cmd_add_trigger},
- { "create", cmd_create},
- { "clear", cmd_clear},
- { "destroy", cmd_destroy},
- { "disable-channel", cmd_disable_channels},
- { "disable-event", cmd_disable_events},
- { "enable-channel", cmd_enable_channels},
- { "enable-event", cmd_enable_events},
- { "help", NULL},
- { "list", cmd_list},
- { "list-triggers", cmd_list_triggers},
- { "load", cmd_load},
- { "metadata", cmd_metadata},
- { "regenerate", cmd_regenerate},
- { "remove-trigger", cmd_remove_trigger},
- { "rotate", cmd_rotate},
- { "enable-rotation", cmd_enable_rotation},
- { "disable-rotation", cmd_disable_rotation},
- { "save", cmd_save},
- { "set-session", cmd_set_session},
- { "snapshot", cmd_snapshot},
- { "start", cmd_start},
- { "status", cmd_status},
- { "stop", cmd_stop},
- { "track", cmd_track},
- { "untrack", cmd_untrack},
- { "version", cmd_version},
- { "view", cmd_view},
- { NULL, NULL} /* Array closure */
-};
-
-static void version(FILE *ofp)
-{
- fprintf(ofp, "%s (LTTng Trace Control) " VERSION" - " VERSION_NAME "%s%s\n",
- progname,
- GIT_VERSION[0] == '\0' ? "" : " - " GIT_VERSION,
- EXTRA_VERSION_NAME[0] == '\0' ? "" : " - " EXTRA_VERSION_NAME);
-}
-
-/*
- * Find the MI output type enum from a string. This function is for the support
- * of machine interface output.
- */
-static int mi_output_type(const char *output_type)
-{
- int ret = 0;
-
- if (!strncasecmp("xml", output_type, 3)) {
- ret = LTTNG_MI_XML;
- } else {
- /* Invalid output format */
- ERR("MI output format not supported");
- ret = -LTTNG_ERR_MI_OUTPUT_TYPE;
- }
-
- return ret;
-}
-
-/*
- * list_options
- *
- * List options line by line. This is mostly for bash auto completion and to
- * avoid difficult parsing.
- */
-static void list_options(FILE *ofp)
-{
- int i = 0;
- struct option *option = NULL;
-
- option = &long_options[i];
- while (option->name != NULL) {
- fprintf(ofp, "--%s\n", option->name);
-
- if (isprint(option->val)) {
- fprintf(ofp, "-%c\n", option->val);
- }
-
- i++;
- option = &long_options[i];
- }
-}
-
-/*
- * clean_exit
- */
-static void clean_exit(int code)
-{
- DBG("Clean exit");
- exit(code);
-}
-
-/*
- * sighandler
- *
- * Signal handler for the daemon
- */
-static void sighandler(int sig)
-{
- switch (sig) {
- case SIGTERM:
- DBG("SIGTERM caught");
- clean_exit(EXIT_FAILURE);
- break;
- default:
- DBG("Unknown signal %d caught", sig);
- break;
- }
-
- return;
-}
-
-/*
- * set_signal_handler
- *
- * Setup signal handler for SIGCHLD and SIGTERM.
- */
-static int set_signal_handler(void)
-{
- int ret = 0;
- struct sigaction sa;
- sigset_t sigset;
-
- if ((ret = sigemptyset(&sigset)) < 0) {
- PERROR("sigemptyset");
- goto end;
- }
-
- sa.sa_handler = sighandler;
- sa.sa_mask = sigset;
- sa.sa_flags = 0;
-
- if ((ret = sigaction(SIGTERM, &sa, NULL)) < 0) {
- PERROR("sigaction");
- goto end;
- }
-
-end:
- return ret;
-}
-
-/*
- * handle_command
- *
- * Handle the full argv list of a first level command. Will find the command
- * in the global commands array and call the function callback associated.
- *
- * If command not found, return -1
- * else, return function command error code.
- */
-static int handle_command(int argc, char **argv)
-{
- int i = 0, ret;
- struct cmd_struct *cmd;
-
- if (*argv == NULL) {
- ret = CMD_SUCCESS;
- goto end;
- }
-
- /* Special case for help command which needs the commands array */
- if (strcmp(argv[0], "help") == 0) {
- ret = cmd_help(argc, (const char**) argv, commands);
- goto end;
- }
-
- cmd = &commands[i];
- while (cmd->name != NULL) {
- /* Find command */
- if (strcmp(argv[0], cmd->name) == 0) {
- ret = cmd->func(argc, (const char**) argv);
- goto end;
- }
- i++;
- cmd = &commands[i];
- }
-
- /* Command not found */
- ret = CMD_UNDEFINED;
-
-end:
- return ret;
-}
-
-static bool command_exists(const char *command)
-{
- const struct cmd_struct *cmd = commands;
- bool exists = false;
-
- while (cmd->name != NULL) {
- if (!strcmp(command, cmd->name)) {
- exists = true;
- goto end;
- }
- cmd++;
- }
-
-end:
- return exists;
-}
-
-static void show_basic_help(void)
-{
- puts("Usage: lttng [--group=GROUP] [--mi=TYPE] [--no-sessiond | --sessiond-path=PATH]");
- puts(" [--quiet | -v | -vv | -vvv] COMMAND [COMMAND OPTIONS]");
- puts("");
- puts("Available commands:");
- puts("");
- puts("Recording sessions:");
- puts(" create " CONFIG_CMD_DESCR_CREATE);
- puts(" clear " CONFIG_CMD_DESCR_CLEAR);
- puts(" destroy " CONFIG_CMD_DESCR_DESTROY);
- puts(" load " CONFIG_CMD_DESCR_LOAD);
- puts(" regenerate " CONFIG_CMD_DESCR_REGENERATE);
- puts(" save " CONFIG_CMD_DESCR_SAVE);
- puts(" set-session " CONFIG_CMD_DESCR_SET_SESSION);
- puts("");
- puts("Channels:");
- puts(" add-context " CONFIG_CMD_DESCR_ADD_CONTEXT);
- puts(" disable-channel " CONFIG_CMD_DESCR_DISABLE_CHANNEL);
- puts(" enable-channel " CONFIG_CMD_DESCR_ENABLE_CHANNEL);
- puts("");
- puts("Recording event rules:");
- puts(" disable-event " CONFIG_CMD_DESCR_DISABLE_EVENT);
- puts(" enable-event " CONFIG_CMD_DESCR_ENABLE_EVENT);
- puts("");
- puts("Status:");
- puts(" list " CONFIG_CMD_DESCR_LIST);
- puts(" status " CONFIG_CMD_DESCR_STATUS);
- puts("");
- puts("Control:");
- puts(" snapshot " CONFIG_CMD_DESCR_SNAPSHOT);
- puts(" start " CONFIG_CMD_DESCR_START);
- puts(" stop " CONFIG_CMD_DESCR_STOP);
- puts("");
- puts("Recording session rotation:");
- puts(" disable-rotation " CONFIG_CMD_DESCR_DISABLE_ROTATION);
- puts(" enable-rotation " CONFIG_CMD_DESCR_ENABLE_ROTATION);
- puts(" rotate " CONFIG_CMD_DESCR_ROTATE);
- puts("");
- puts("Resource tracking:");
- puts(" track " CONFIG_CMD_DESCR_TRACK);
- puts(" untrack " CONFIG_CMD_DESCR_UNTRACK);
- puts("");
- puts("Triggers:");
- puts(" add-trigger " CONFIG_CMD_DESCR_ADD_TRIGGER);
- puts(" remove-trigger " CONFIG_CMD_DESCR_REMOVE_TRIGGER);
- puts(" list-triggers " CONFIG_CMD_DESCR_LIST_TRIGGERS);
- puts("");
- puts("Miscellaneous:");
- puts(" help " CONFIG_CMD_DESCR_HELP);
- puts(" version " CONFIG_CMD_DESCR_VERSION);
- puts(" view " CONFIG_CMD_DESCR_VIEW);
- puts("");
- puts("Run `lttng help COMMAND` or `lttng COMMAND --help` to get help with");
- puts("command COMMAND.");
- puts("");
- puts("See `man lttng` for more help with the lttng command.");
-}
-
-/*
- * Parse command line arguments.
- *
- * Return 0 if OK, else -1
- */
-static int parse_args(int argc, char **argv)
-{
- int opt, ret;
-
- if (lttng_is_setuid_setgid()) {
- ERR("'%s' is not allowed to be executed as a setuid/setgid binary for security reasons. Aborting.", argv[0]);
- clean_exit(EXIT_FAILURE);
- }
-
- if (argc < 2) {
- show_basic_help();
- clean_exit(EXIT_FAILURE);
- }
-
- while ((opt = getopt_long(argc, argv, "+Vhnvqg:m:", long_options, NULL)) != -1) {
- switch (opt) {
- case 'V':
- version(stdout);
- ret = 0;
- goto end;
- case 'h':
- ret = utils_show_help(1, "lttng", help_msg);
- if (ret) {
- ERR("Cannot show --help for `lttng`");
- perror("exec");
- }
- goto end;
- case 'v':
- /* There is only 3 possible level of verbosity. (-vvv) */
- if (lttng_opt_verbose < 3) {
- lttng_opt_verbose += 1;
- }
- break;
- case 'q':
- lttng_opt_quiet = 1;
- break;
- case 'm':
- lttng_opt_mi = mi_output_type(optarg);
- if (lttng_opt_mi < 0) {
- ret = lttng_opt_mi;
- goto error;
- }
- break;
- case 'g':
- lttng_set_tracing_group(optarg);
- break;
- case 'n':
- opt_no_sessiond = 1;
- break;
- case OPT_SESSION_PATH:
- free(opt_sessiond_path);
- opt_sessiond_path = strdup(optarg);
- if (!opt_sessiond_path) {
- ret = -1;
- goto error;
- }
- break;
- case OPT_RELAYD_PATH:
- free(opt_relayd_path);
- opt_relayd_path = strdup(optarg);
- if (!opt_relayd_path) {
- ret = -1;
- goto error;
- }
- break;
- case OPT_DUMP_OPTIONS:
- list_options(stdout);
- ret = 0;
- goto end;
- case OPT_DUMP_COMMANDS:
- list_commands(commands, stdout);
- ret = 0;
- goto end;
- default:
- ret = 1;
- goto error;
- }
- }
-
- /* If both options are specified, quiet wins */
- if (lttng_opt_verbose && lttng_opt_quiet) {
- lttng_opt_verbose = 0;
- }
-
- /* No leftovers, quit */
- if ((argc - optind) == 0) {
- ret = 1;
- goto error;
- }
-
- /*
- * Handle leftovers which is a first level command with the trailing
- * options.
- */
- ret = handle_command(argc - optind, argv + optind);
- switch (ret) {
- case CMD_WARNING:
- case CMD_ERROR:
- break;
- case CMD_UNDEFINED:
- if (!command_exists(*(argv + optind))) {
- MSG("lttng: %s is not an lttng command. See 'lttng --help'.",
- *(argv + optind));
- } else {
- ERR("Unrecognized argument used with \'%s\' command",
- *(argv + optind));
- }
- break;
- case CMD_FATAL:
- case CMD_UNSUPPORTED:
- break;
- case -1:
- ret = 1;
- break;
- case 0:
- break;
- default:
- if (ret < 0) {
- ret = -ret;
- }
- break;
- }
-
-end:
-error:
- return ret;
-}
-
-
-/*
- * main
- */
-int main(int argc, char *argv[])
-{
- int ret;
-
- progname = argv[0] ? argv[0] : "lttng";
-
- ret = set_signal_handler();
- if (ret < 0) {
- clean_exit(ret);
- }
-
- ret = parse_args(argc, argv);
- if (ret != 0) {
- clean_exit(ret);
- }
-
- return 0;
-}